From 84f9d7a4ea6e7921d46e7fe6e69a4f424ccfb55b Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 6 May 2024 08:59:21 +0800 Subject: [PATCH 01/15] no message --- .../lib/components/PictureOverview.dart | 332 ++++-------------- marking_app/lib/pages/marking/do_papers.dart | 207 ++++------- 2 files changed, 144 insertions(+), 395 deletions(-) diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 545f4c5..447df53 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -165,8 +165,7 @@ class PictureOverviewState extends ConsumerState with CommonMix crypto.Digest fileMd5 = crypto.md5.convert(await temFile!.readAsBytes()); RestClient _client = await getClient(); - BaseStructureResult resUploadConfig = - await _client.getUploadFile(UploadFileInterfaceConfigParams( + BaseStructureResult resUploadConfig = await _client.getUploadFile(UploadFileInterfaceConfigParams( fileName: '1.png', fileMd5: fileMd5.toString(), contentLength: temFile!.lengthSync(), @@ -179,8 +178,7 @@ class PictureOverviewState extends ConsumerState with CommonMix if (resUploadConfig.data!.uploadUri == null) { return FileResult(myObject: '', success: true, url: resUploadConfig.data!.downloadUri); } - FileResult? resFile = - await ref.read(uploadFileProvider.notifier).getUploadFileConfig(resUploadConfig.data!, temFile!); + FileResult? resFile = await ref.read(uploadFileProvider.notifier).getUploadFileConfig(resUploadConfig.data!, temFile!); // FileResult? resFile = await ref // .read(uploadFileProvider.notifier) // .uploadFile(temFile!.path, widget.imageItems[currentIndex], ref.read(userProvider).id.toString()); @@ -230,7 +228,6 @@ class PictureOverviewState extends ConsumerState with CommonMix @override Widget build(BuildContext context) { - DoMarkingKeyboardModel _model = ref.watch(markingKeyboardProvider); return Container( width: double.infinity, height: double.infinity, @@ -259,8 +256,7 @@ class PictureOverviewState extends ConsumerState with CommonMix }, imageBuilder: (context, imageProvider) { Image imageWidget = Image(image: imageProvider, fit: BoxFit.fitWidth); - if (imagInfoModel == null || - (imagInfoModel?.boxHeight != containerHeight || imagInfoModel?.boxWidth != containerWidth)) { + if (imagInfoModel == null || (imagInfoModel?.boxHeight != containerHeight || imagInfoModel?.boxWidth != containerWidth)) { if (_imageStreamListener != null) _imageStream?.removeListener(_imageStreamListener!); _imageStreamListener = ImageStreamListener((ImageInfo info, bool _) { imagInfoModel = TestQuestionsImageInfo( @@ -303,24 +299,25 @@ class PictureOverviewState extends ConsumerState with CommonMix // 试卷绘制 class ExamPaperDrawing extends StatefulHookConsumerWidget { - String imgUrl; + // String imgUrl; bool homework; BoxDecoration? decoration; AnnotationGraffitiSwitch graffitiSwitch; List? points; List? pointsPureData; ValueNotifier> imageLoaded; - + Widget child; GlobalKey globalKey; // Function(String) imageCall; ExamPaperDrawing({ - required this.imgUrl, + // required this.imgUrl, required this.homework, required this.points, required this.pointsPureData, required this.graffitiSwitch, required this.globalKey, required this.imageLoaded, + required this.child, this.decoration, Key? key, }) : super(key: key); @@ -329,54 +326,17 @@ class ExamPaperDrawing extends StatefulHookConsumerWidget { _ExamPaperDrawingState createState() => _ExamPaperDrawingState(); } -class _ExamPaperDrawingState extends ConsumerState - with EventBusMixin { - late Future _future; // 考试试卷 - +class _ExamPaperDrawingState extends ConsumerState with EventBusMixin { // 用于记录手指位置的变量 late List points; late List pointsPureData; // 用于记录绘图结果的变量 - bool _isEraserPressed = false; // 橡皮擦按下 - Offset? _eraserPosition; // 按下位置 - Offset? globalPosition = null; // 是否正在绘制 - - Future loadImage(String url) async { - try { - Map map = widget.imageLoaded.value; - ui.Image? image = map[url]; - if (image != null) { - return image; - } - final httpClient = HttpClient(); - final request = await httpClient.getUrl(Uri.parse(url)); - final response = await request.close(); - final bytes = await consolidateHttpClientResponseBytes(response); - final codec = await ui.instantiateImageCodec(bytes); - final frame = await codec.getNextFrame(); - ui.Image theImage = frame.image; - map[url] = theImage; - return theImage; - } catch (e) { - print('请求图片报错:${e.toString()}'); - } - return null; - } - - // void _onPointerDown(DragDownDetails details) { - // if (widget.graffitiSwitch.openEraser) { - // _eraserPosition = (context.findRenderObject() as RenderBox).globalToLocal(details.globalPosition); - // _isEraserPressed = true; - // toUpState(setState, ()=>{}, mounted); - // } - // } + Offset? globalPosition; // 是否正在绘制 @override void initState() { points = widget.points ?? []; pointsPureData = widget.pointsPureData ?? []; - print('图片地址:${widget.imgUrl}'); - _future = loadImage(widget.imgUrl); // 事件总线监听 eventOn(callback: (BottomAnnotationSwitchCleanall item) { if (item.previousStep) { @@ -434,190 +394,79 @@ class _ExamPaperDrawingState extends ConsumerState @override Widget build(BuildContext context) { - return MyFutureBuilder.buildFutureBuilderOfSingleInstance( - context, - _future, - (ui.Image? theImage) { - if (theImage == null) return const Center(child: Text('图片加载错误')); + return Listener( + behavior: HitTestBehavior.opaque, + onPointerMove: (PointerMoveEvent details) { + if (globalPosition != null) { + // 预防双指同时作用于屏幕 + double dx = globalPosition!.dx; + double dy = globalPosition!.dy; - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - final double containerWidth = constraints.maxWidth; // 展示区域总宽度 - final double containerHeight = constraints.maxHeight; // 展示区域总宽度 - - final double imageWidth = theImage.width.toDouble(); // 图片原始宽度 - final double imageHeight = theImage.height.toDouble(); // 图片原始高度 - final double widthRatio = containerWidth / imageWidth; // - final double heightRatio = containerHeight / imageHeight; - final double scale = widthRatio > heightRatio ? heightRatio : widthRatio; - final double destWidth = imageWidth * scale; - final double destHeight = imageHeight * scale; - - final bool homework = widget.homework; - - return GestureDetector( - behavior: HitTestBehavior.opaque, - onPanUpdate: (DragUpdateDetails details) { - if (globalPosition != null) { - // 预防双指同时作用于屏幕 - double dx = globalPosition!.dx; - double dy = globalPosition!.dy; - - double dxNew = details.globalPosition.dx; - double dyNew = details.globalPosition.dy; - if ((dxNew - dx).abs() > 22 || (dyNew - dy).abs() > 22) { - return; - } - } - globalPosition = details.globalPosition; - try { - if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { - RenderBox renderBox = context.findRenderObject() as RenderBox; - Offset localPosition = renderBox.globalToLocal(details.globalPosition); - pointsPureData = List.from(pointsPureData)..add(localPosition); - points = List.from(points) - ..add(GestureRecording(eraser: widget.graffitiSwitch.openEraser, data: localPosition)); - _eraserPosition = localPosition; - _isEraserPressed = true; - setState(() {}); - } - } catch (e) { - toPrint(val: '进入报错'); - } - }, - onPanEnd: (DragEndDetails details) { - print('离开.............'); - globalPosition = null; - if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { - pointsPureData.add(null); // 增加空点以分隔不同的线段 - points.add(GestureRecording(eraser: widget.graffitiSwitch.openEraser)); - _isEraserPressed = false; - _eraserPosition = null; - } - }, - child: RepaintBoundary( - key: widget.globalKey, - child: CustomPaint( - // isComplex: true, - // willChange: true, - painter: DrawingPainter( - image: theImage, - points: points, - isErasing: widget.graffitiSwitch.openEraser, - destWidth: destWidth, - destHeight: destHeight, - imageWidth: imageWidth, - imageHeight: imageHeight, - homework: homework, - containerWidth: containerWidth, - containerHeight: containerHeight, - ), - // size: Size(homework ? containerWidth : destWidth, homework ? containerHeight : destHeight), - size: Size(containerWidth, containerHeight), - ), - ), - ); - }, - ); + 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, + ), + ), ); } } class DrawingPainter extends CustomPainter { final List points; - final bool isErasing; - final ui.Image image; - final bool homework; - final double containerWidth; - final double containerHeight; - double destWidth; - double destHeight; - final double imageWidth; - final double imageHeight; + DrawingPainter({required this.points}) : super(); - // final Rect destRect; - // final Rect srcRect; - final bool openErasing; - DrawingPainter({ - required this.homework, - required this.points, - required this.isErasing, - required this.image, - required this.destWidth, - required this.destHeight, - required this.containerWidth, - required this.containerHeight, - required this.imageWidth, - required this.imageHeight, - }) : - // destRect = Rect.fromLTWH(0, 0,destWidth,destHeight), - // srcRect = Rect.fromLTWH(0, 0, imageWidth, imageHeight), - openErasing = points.isNotEmpty && isErasing, - super(); - - Paint paintBrush = Paint() + final Paint paintBrush = Paint() ..color = Colors.red ..strokeCap = StrokeCap.round - ..strokeWidth = 1.5; - - Paint eraser = Paint() - ..blendMode = BlendMode.clear - ..color = Colors.transparent - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round - ..strokeWidth = 100; - - final emptyPaint = Paint(); - final emptyPaintWithWidth = Paint()..strokeWidth = 60.0; + ..strokeWidth = 1.5.r; @override void paint(Canvas canvas, Size size) { - double offsetX = (size.width - destWidth) / 2; - double offsetY = (size.height - destHeight) / 2; - if (destWidth < (size.width / 2)) { - destWidth = size.width / 2; - offsetX = (size.width - destWidth) / 2; - } - - // final rect = Rect.fromCenter(center: center, width: destWidth, height: destHeight); - Rect srcRect = Rect.fromLTRB(0, 0, image.width.toDouble(), image.height.toDouble()); - // Rect destRect = Rect.fromLTRB(offsetX, offsetY, containerWidth, containerHeight); - Rect destRect = Offset(offsetX, offsetY) & Size(destWidth, destHeight); - - canvas.drawImageRect(image, srcRect, destRect, emptyPaint); - - // canvas.drawImage(image, Offset.zero, emptyPaint); - if (points.isNotEmpty) { - // canvas.saveLayer(destRect, emptyPaintWithWidth); // 只绘制图片大小区域 - canvas.saveLayer(Rect.largest, emptyPaintWithWidth); // 整个视图区域 - - canvas.drawColor(Colors.transparent, BlendMode.clear); - } - - for (int i = 0; i < points.length - 1; i++) { + print('数据.....................'); + for (int i = 0; i < points.length; i++) { GestureRecording item = points[i]; GestureRecording nextItem = points[i + 1]; Offset? offsetData = item.data; Offset? nextOffsetData = nextItem.data; if (offsetData != null && nextOffsetData != null) { - canvas.drawLine(offsetData, nextOffsetData, !item.eraser ? paintBrush : eraser); + canvas.drawLine(offsetData, nextOffsetData, paintBrush); } } - - // 恢复画布状态. - if (points.isNotEmpty) canvas.restore(); } - // @override - // bool shouldRepaint(DrawingPainter oldDelegate) { - // List thePoints = oldDelegate.points; - // // var flag = oldDelegate.points != points || oldDelegate.isErasing != isErasing; - // return thePoints != points; - // } - @override - bool shouldRepaint(DrawingPainter oldDelegate) => true; + bool shouldRepaint(DrawingPainter oldDelegate) { + return oldDelegate.points.length != points.length || oldDelegate.points != points; + } } /** @@ -802,9 +651,7 @@ Widget $localAndNetworkSwitch( useValueChanged(drawFlag, (oldValue, oldResult) { if (!drawFlag) { // 关闭的时候创建临时图片文件在设备 - _useSwitch - .createTempFile(context, theglobalKey: theglobalKey, examGlobalKey: examGlobalKey) - .then((File? theFile) { + _useSwitch.createTempFile(context, theglobalKey: theglobalKey, examGlobalKey: examGlobalKey).then((File? theFile) { if (theFile == null) { // TODO 代表保存失败的逻辑 // 当前情况:_useSwich.showZoomImg.value 没有设置为true还是展示的原来的绘图组件ExamPaperDrawing @@ -832,50 +679,23 @@ Widget $localAndNetworkSwitch( }, []); print('是否更新视图.... ${_useZoomHistory.initPosition.value}'); - return _useSwitch.showZoomImg.value - ? - /** - Scrollbar( - // thumbVisibility: true, - thumbVisibility: true, - controller: _useScrollController, - child: SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.zero, - scrollDirection: Axis.vertical, // 设置垂直滚动 - child: Transform.scale( - scale: 0.4, - alignment: Alignment.topCenter, - child: $MyCachedNetworkImage( - imageUrl: imageUrl, - tempFile: _useSwitch.temFile.value, - width: containerWidth, - height: containerHeight, - ), - ), - ), - )*/ - - /** */ - $MyCachedNetworkImage( - imageUrl: imageUrl, - tempFile: _useSwitch.temFile.value, - width: containerWidth, - height: containerHeight, - imageBuilder: imageBuilder, - ) - : ExamPaperDrawing( - imgUrl: imageUrl, - 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, - // imageCall: (String str) => widget.imageCall(str, currentIndex), - ); + 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, + ), + ); } class UseLocalAndNetworkSwitch { diff --git a/marking_app/lib/pages/marking/do_papers.dart b/marking_app/lib/pages/marking/do_papers.dart index 366d583..335bdf4 100644 --- a/marking_app/lib/pages/marking/do_papers.dart +++ b/marking_app/lib/pages/marking/do_papers.dart @@ -44,6 +44,7 @@ import 'package:marking_app/common/model/marking/submit_exam_small_params.dart'; import 'package:marking_app/common/model/marking/switch_keyboard_to_reload_images.dart'; import 'package:marking_app/components/PictureOverview.dart'; +import 'package:marking_app/components/marking/bottom_annotation_switch.dart'; import 'package:marking_app/components/marking/marking_keyboard_switch.dart'; import 'package:marking_app/components/marking/marking_question_type_drawer.dart'; import 'package:marking_app/components/marking/marking_seting.dart'; @@ -174,9 +175,8 @@ class _MarkingPapersState extends ConsumerState screenDirectionSwitch(state.screenDirection); } else { ScreenDirection nowScreenDirection = state.screenDirection; // 当前屏幕方向 - ScreenDirection theOrientation = MediaQuery.of(context).orientation == Orientation.landscape - ? ScreenDirection.HORIZONTAL_SCREEN - : ScreenDirection.VERTICAL_SCREEN; + ScreenDirection theOrientation = + MediaQuery.of(context).orientation == Orientation.landscape ? ScreenDirection.HORIZONTAL_SCREEN : ScreenDirection.VERTICAL_SCREEN; if (theOrientation != nowScreenDirection) { screenDirectionSwitch(nowScreenDirection); } @@ -243,8 +243,7 @@ class _MarkingPapersState extends ConsumerState bool isHorizontal = direction == ScreenDirection.HORIZONTAL_SCREEN; Future.delayed(Duration.zero, () { - SystemChrome.setPreferredOrientations( - [isHorizontal ? DeviceOrientation.landscapeLeft : DeviceOrientation.portraitUp]); + SystemChrome.setPreferredOrientations([isHorizontal ? DeviceOrientation.landscapeLeft : DeviceOrientation.portraitUp]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); setTimeOut(1000, () => toUpState(setState, () => annotationsFlag = true, mounted)); }); @@ -260,8 +259,7 @@ class _MarkingPapersState extends ConsumerState return null; } currentQuestion!.papersUrlStr = paperUrls; - currentQuestion!.papersUrl = - paperUrls.asMap().keys.map((e) => GalleryExampleItemModel(id: e.toString(), resource: paperUrls[e])).toList(); + currentQuestion!.papersUrl = paperUrls.asMap().keys.map((e) => GalleryExampleItemModel(id: e.toString(), resource: paperUrls[e])).toList(); return currentQuestion!.papersUrl; } @@ -426,8 +424,7 @@ class _MarkingPapersState extends ConsumerState Future submitTestQuestions(BuildContext theContext, MarkingTextQuestion data) async { Timer timer = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); try { - if (widget.markingtype == MarkingListType.NORMAL && currentQuestion!.isException) - return ToastUtils.showError('异常题,不允许再评分'); + if (widget.markingtype == MarkingListType.NORMAL && currentQuestion!.isException) return ToastUtils.showError('异常题,不允许再评分'); if (currentQuestion == null) { return ToastUtils.showError('提交失败,请退出重试。'); @@ -762,8 +759,7 @@ class _MarkingPapersState extends ConsumerState bool isReview = widget.isReview; if (theId != null && _currentTab != null && theQuestionNum != _currentTab!.questionNum) { - MarkingTextQuestionTab? _foundCrrentTab = - _currentTabs.firstWhereOrNull((element) => element.questionNum == theQuestionNum); + MarkingTextQuestionTab? _foundCrrentTab = _currentTabs.firstWhereOrNull((element) => element.questionNum == theQuestionNum); if (_foundCrrentTab != null) { _currentTab = _foundCrrentTab; } @@ -791,11 +787,7 @@ class _MarkingPapersState extends ConsumerState // 同步小题得分 score:分值 continueScoring:是否可以持续打分 hasSubtopic:是否有小题; cleanScore:是否是清空 Future synchroScore( - {required double score, - required bool continueScoring, - required bool hasSubtopic, - bool allWrong = false, - bool cleanScore = false}) async { + {required double score, required bool continueScoring, required bool hasSubtopic, bool allWrong = false, bool cleanScore = false}) async { if (currentQuestion == null) return; if (cleanScore) { @@ -879,8 +871,8 @@ class _MarkingPapersState extends ConsumerState res.data = res.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList(); // 方便更新tags key是题号 - Map _currentTabsMap = Map.fromIterable(_currentTabs, - key: (item) => item.questionNum, value: (item) => item); + Map _currentTabsMap = + Map.fromIterable(_currentTabs, key: (item) => item.questionNum, value: (item) => item); MarkingTextQuestionTab? theCurrentTab; String currentTagQueNum = _currentTab!.questionNum; res.data!.forEach((e) { @@ -918,31 +910,25 @@ class _MarkingPapersState extends ConsumerState if (!widget.exceptional && _currentTabs.length <= 0 && _currentTab == null) { // tag为空,请求tag数据并且为对应的tag赋值上分值步长 RestClient client = await getClient(); - List res = await Future.wait([ - client.getTestQuestionsOfTab(widget.markingUserId), - client.getTestQuestionsOfTabStepSize(widget.examSubjectId) - ]); - BaseStructureResult> resultTab = - res[0] as BaseStructureResult>; - BaseStructureResult> resultTabStep = - res[1] as BaseStructureResult>; + List res = + await Future.wait([client.getTestQuestionsOfTab(widget.markingUserId), client.getTestQuestionsOfTabStepSize(widget.examSubjectId)]); + BaseStructureResult> resultTab = res[0] as BaseStructureResult>; + BaseStructureResult> resultTabStep = res[1] as BaseStructureResult>; if ((!resultTab.success || (resultTab.data?.isEmpty ?? true)) || (!resultTabStep.success || (resultTabStep.data?.isEmpty ?? true)) || (resultTabStep.data!.length < resultTab.data!.length)) { throw Error(); } - Map tabStepMap = Map.fromIterable(resultTabStep.data!, - key: (item) => item.questionNum, value: (item) => item.scoreInterval); + Map tabStepMap = + Map.fromIterable(resultTabStep.data!, key: (item) => item.questionNum, value: (item) => item.scoreInterval); resultTab.data = resultTab.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList(); resultTab.data!.forEach((element) => element.setStepSize(tabStepMap[element.questionNum] ?? 1.0)); _currentTabs = resultTab.data!; // 获取当前tabs批次下第一个没有完成数据 - currentTab = resultTab.data!.firstWhere( - tabQuestionNum == null ? firstWhereCall : (e) => e.questionNum == tabQuestionNum, - orElse: () => - MarkingTextQuestionTab(isFinished: false, questionNum: '0.0', total: 0, finishCount: 0, isExcess: false)); + currentTab = resultTab.data!.firstWhere(tabQuestionNum == null ? firstWhereCall : (e) => e.questionNum == tabQuestionNum, + orElse: () => MarkingTextQuestionTab(isFinished: false, questionNum: '0.0', total: 0, finishCount: 0, isExcess: false)); if (currentTab.questionNum == '0.0') { // 全部都批改完成了,默认tab设置为第一个 @@ -1025,8 +1011,7 @@ class _MarkingPapersState extends ConsumerState if (hasNext) { // 查找下一个tab return _currentTabs.firstWhere(firstWhereCall, - orElse: () => MarkingTextQuestionTab( - questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false)); + orElse: () => MarkingTextQuestionTab(questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false)); } if (tabQuestionNum != null) { @@ -1036,8 +1021,7 @@ class _MarkingPapersState extends ConsumerState if (resetting) { // 是否进行重置,继续阅卷 MarkingTextQuestionTab theMarking = _currentTabs.firstWhere(firstWhereCall, - orElse: () => MarkingTextQuestionTab( - questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false)); + orElse: () => MarkingTextQuestionTab(questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false)); if (theMarking.questionNum != '0.0') { currentTab = theMarking; } @@ -1143,8 +1127,8 @@ class _MarkingPapersState extends ConsumerState currentQuestion = result.data; if (temTab != null) { result.data!.scoreInterval = temTab.scoreInterval ?? 1; - MarkingZoom? markingZoom = await UseZoomImageHistoryUtils.getZoomImageInfo( - widget.markingUserId.toString() + '-' + (currentQuestion?.questionNum.toString() ?? '')); + MarkingZoom? markingZoom = + await UseZoomImageHistoryUtils.getZoomImageInfo(widget.markingUserId.toString() + '-' + (currentQuestion?.questionNum.toString() ?? '')); if (markingZoom != null) { imageScale = double.parse(markingZoom.scale.toStringAsFixed(2)); imagePosition = Offset( @@ -1232,8 +1216,7 @@ class _MarkingPapersState extends ConsumerState if (firstComeIn) setTimeOut(2000, () => firstComeIn = false); if (ref.read(markingSubtopicSwitchingProvider.notifier).state != activeQuestIndex) { // 重置小题题号位置下标 - Future.delayed( - Duration.zero, () => ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex)); + Future.delayed(Duration.zero, () => ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex)); } if (currentQuestion != null && widget.markingtype == MarkingListType.EXCEPTIONAL) { BaseStructureResult res = await client.getMarkingQuestionsErrorInfo(currentQuestion!.id); @@ -1435,8 +1418,7 @@ class _MarkingPapersState extends ConsumerState bool isNormal = !widget.exceptional; // 正常批题 bool notNextTest = data.nextId == 0; // 没有下一个试题了 // 下一题点击触发的方法 - var pressedNextTest = - notNextTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh(isNext: true)); + var pressedNextTest = notNextTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh(isNext: true)); bool notHasPreviousTest = data.prevId == 0; /** 无需根据当前位置判断 @@ -1501,8 +1483,7 @@ class _MarkingPapersState extends ConsumerState color: const Color.fromRGBO(148, 163, 182, 1), ), ), - if (_currentTab!.isExcess && - _currentTab!.finishCount > _currentTab!.total) + if (_currentTab!.isExcess && _currentTab!.finishCount > _currentTab!.total) Container( margin: EdgeInsets.only(left: 4.w), child: Row( @@ -1513,8 +1494,7 @@ class _MarkingPapersState extends ConsumerState color: const Color.fromRGBO(148, 163, 182, 1), ), quickText( - (_currentTab!.finishCount - _currentTab!.total) - .toString(), + (_currentTab!.finishCount - _currentTab!.total).toString(), size: isBroadwise ? 18.sp : 14.sp, color: Color.fromRGBO(251, 144, 84, 1), ), @@ -1540,19 +1520,16 @@ class _MarkingPapersState extends ConsumerState ), ), SizedBox(width: 8.w), - if (model.hideQuestionId && - model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN) + if (model.hideQuestionId && model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN) InkWell( onTap: () { - Clipboard.setData(ClipboardData(text: data.paperNum ?? '')) - .then((value) { + Clipboard.setData(ClipboardData(text: data.paperNum ?? '')).then((value) { ToastUtils.showSuccess('试卷编号已复制'); }); }, child: Row( children: [ - quickText('试卷编号: ', - size: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + quickText('试卷编号: ', size: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), quickText( data.paperNum ?? '', size: 16.sp, @@ -1585,8 +1562,7 @@ class _MarkingPapersState extends ConsumerState color: const Color.fromRGBO(4, 201, 208, 1), ), ), - if (isBroadwise && widget.markingtype == MarkingListType.EXCEPTIONAL || - data.isException) + if (isBroadwise && widget.markingtype == MarkingListType.EXCEPTIONAL || data.isException) Container( padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 2.h), color: const Color.fromRGBO(245, 108, 108, 0.236), @@ -1630,18 +1606,14 @@ class _MarkingPapersState extends ConsumerState size: isBroadwise ? 15.sp : 12.sp, ), SizedBox(width: 1.w), - quickText('继续阅卷', - color: const Color.fromRGBO(80, 87, 103, 1), - size: isBroadwise ? 15.sp : 12.sp), + quickText('继续阅卷', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp), ], ), ), SizedBox(width: 10.w), InkWell( onTap: () { - ref - .read(ratingProgressProvider.notifier) - .setState(EndDrawerViewEnum.REVIEW_RECORD); + ref.read(ratingProgressProvider.notifier).setState(EndDrawerViewEnum.REVIEW_RECORD); scaffoldKey.currentState?.openEndDrawer(); }, child: Row( @@ -1652,9 +1624,7 @@ class _MarkingPapersState extends ConsumerState size: isBroadwise ? 15.sp : 12.sp, ), SizedBox(width: 1.w), - quickText('阅卷记录', - color: const Color.fromRGBO(80, 87, 103, 1), - size: isBroadwise ? 15.sp : 12.sp), + quickText('阅卷记录', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp), ], ), ), @@ -1666,9 +1636,7 @@ class _MarkingPapersState extends ConsumerState ), InkWell( onTap: () { - ref - .read(ratingProgressProvider.notifier) - .setState(EndDrawerViewEnum.RATING_PROGRESS); + ref.read(ratingProgressProvider.notifier).setState(EndDrawerViewEnum.RATING_PROGRESS); scaffoldKey.currentState?.openEndDrawer(); }, child: Row( @@ -1679,9 +1647,7 @@ class _MarkingPapersState extends ConsumerState size: isBroadwise ? 15.sp : 12.sp, ), SizedBox(width: 1.w), - quickText('评分进度', - color: const Color.fromRGBO(80, 87, 103, 1), - size: isBroadwise ? 15.sp : 12.sp), + quickText('评分进度', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp), ], ), ), @@ -1690,8 +1656,7 @@ class _MarkingPapersState extends ConsumerState InkWell( onTap: () { if (data.isException) { - return ToastUtils.getFluttertoast( - context: context, msg: '当前试题已为异常题,无需重复提交'); + return ToastUtils.getFluttertoast(context: context, msg: '当前试题已为异常题,无需重复提交'); } toUpState(setState, () => showAbnormal = true, mounted); }, @@ -1817,17 +1782,14 @@ class _MarkingPapersState extends ConsumerState return InkWell( onTap: () { double? getScore = quest.subQuestionGotScore; - ref - .read(markingSubtopicSwitchingProvider.notifier) - .setVal(index); + ref.read(markingSubtopicSwitchingProvider.notifier).setVal(index); toUpState(setState, () { activeQuestIndex = index; // TODO 这是什么 // pictureOverviewKey.currentState?.jumpToPage(activeQuestIndex); questScore = getScore?.toString() ?? ''; - hasZeroPointFive = - questScore != '' && getScore! >= quest.subQuestionScore; + hasZeroPointFive = questScore != '' && getScore! >= quest.subQuestionScore; }, mounted); }, child: Container( @@ -1848,8 +1810,7 @@ class _MarkingPapersState extends ConsumerState alignment: const FractionalOffset(0.5, 1.78), children: [ Container( - padding: EdgeInsets.symmetric( - horizontal: 4.w, vertical: 8.h), + padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h), alignment: Alignment.center, decoration: BoxDecoration( color: !activeIndex @@ -1871,9 +1832,7 @@ class _MarkingPapersState extends ConsumerState maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( - color: activeIndex - ? Colors.white - : const Color.fromRGBO(80, 87, 103, 1), + color: activeIndex ? Colors.white : const Color.fromRGBO(80, 87, 103, 1), fontSize: 13.sp, fontWeight: FontWeight.w500, ), @@ -1884,22 +1843,18 @@ class _MarkingPapersState extends ConsumerState child: quickText( '(${getDoubleRemoveZero(data.subQuestionDetailList[index].subQuestionScore)})', size: 11.sp, - color: activeIndex - ? Colors.white - : const Color.fromRGBO( - 80, 87, 103, 1)), + color: + activeIndex ? Colors.white : const Color.fromRGBO(80, 87, 103, 1)), ) ], )), if (activeIndex) Icon(Icons.arrow_drop_down_outlined, - color: const Color.fromRGBO(46, 91, 255, 1), - size: 20.sp) + color: const Color.fromRGBO(46, 91, 255, 1), size: 20.sp) ], ), Container( - padding: - EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h), + padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h), alignment: Alignment.center, child: Text( getDoubleRemoveZero(quest.subQuestionGotScore, '请评分'), @@ -1945,8 +1900,7 @@ class _MarkingPapersState extends ConsumerState ), child: Text( '>>', - style: - TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp), + style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp), ), )), onHorizontalDragEnd: (detail) { @@ -1976,7 +1930,7 @@ class _MarkingPapersState extends ConsumerState imageItems: data.getImageData(), ), ), - // 批注开关 暂时注释 + // 批注开关 暂时注释 TODO // if (!showSetingFlag && // !widget.exceptional && // currentQuestion != null && @@ -1986,7 +1940,7 @@ class _MarkingPapersState extends ConsumerState // Positioned( // left: 0, // bottom: 0, - // child: BottomAnnotationSwitch(maxWidth: maxWidth - 1.5.w), + // child: BottomAnnotationSwitch(maxWidth: ScreenUtil().screenWidth - 1.5.w), // ), // 大题评分展示框 if (!hasSubtopic) @@ -2000,10 +1954,7 @@ class _MarkingPapersState extends ConsumerState color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1), child: Container( padding: EdgeInsets.symmetric( - horizontal: (data.score == null || - (getDoubleRemoveZero(data.score ?? 0)).length >= 2) - ? 4.w - : 12.w, + horizontal: (data.score == null || (getDoubleRemoveZero(data.score ?? 0)).length >= 2) ? 4.w : 12.w, vertical: 6.h), alignment: Alignment.center, child: Text( @@ -2029,15 +1980,11 @@ class _MarkingPapersState extends ConsumerState color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1), child: Container( padding: EdgeInsets.symmetric( - horizontal: (data.score == null || - (getDoubleRemoveZero(data.score ?? 0)).length >= 2) - ? 4.w - : 12.w, + horizontal: (data.score == null || (getDoubleRemoveZero(data.score ?? 0)).length >= 2) ? 4.w : 12.w, vertical: 6.h), alignment: Alignment.center, child: Text( - getDoubleRemoveZero(data.score, - '请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}'), + getDoubleRemoveZero(data.score, '请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}'), style: TextStyle( fontSize: 18.sp, color: const Color.fromRGBO(46, 91, 255, 1), @@ -2047,22 +1994,17 @@ class _MarkingPapersState extends ConsumerState ), ), // 上一题 按钮 - if (widget.markingtype != MarkingListType.EXCEPTIONAL && - !_theOldAnnotationGraffiti && - !notHasPreviousTest) + if (widget.markingtype != MarkingListType.EXCEPTIONAL && !_theOldAnnotationGraffiti && !notHasPreviousTest) Positioned( left: 3.w, top: ScreenUtil().setHeight(MediaQuery.of(context).size.height) / 2 * 0.87, child: FloatingActionButton( tooltip: '前往上一题', - backgroundColor: notHasPreviousTest - ? const Color.fromRGBO(24, 32, 32, 0.04) - : const Color.fromRGBO(24, 32, 32, 0.1), + backgroundColor: + notHasPreviousTest ? const Color.fromRGBO(24, 32, 32, 0.04) : const Color.fromRGBO(24, 32, 32, 0.1), focusColor: Theme.of(context).primaryColor, elevation: 0, - onPressed: notHasPreviousTest - ? null - : () => easyThrottle('TestQuestionSwitch', () => refresh()), + onPressed: notHasPreviousTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh()), child: const Icon(Icons.arrow_back_ios, color: Colors.white), heroTag: 'other', ), @@ -2075,9 +2017,8 @@ class _MarkingPapersState extends ConsumerState child: FloatingActionButton( elevation: 0, tooltip: '点击前往下一题', - backgroundColor: notNextTest - ? const Color.fromRGBO(24, 32, 32, 0.04) - : const Color.fromRGBO(24, 32, 32, 0.1), + backgroundColor: + notNextTest ? const Color.fromRGBO(24, 32, 32, 0.04) : const Color.fromRGBO(24, 32, 32, 0.1), foregroundColor: Colors.white, onPressed: pressedNextTest, child: const Icon(Icons.arrow_forward_ios, color: Colors.white), @@ -2169,8 +2110,7 @@ class _MarkingPapersState extends ConsumerState // 异常显示区域 $AbnormalBox( - businessHandle: (bool flag, String? reasonKey, String? otherReasons) => - initiateException(flag, reasonKey, otherReasons), + businessHandle: (bool flag, String? reasonKey, String? otherReasons) => initiateException(flag, reasonKey, otherReasons), isBroadwise: isBroadwise, showAbnormal: !showAbnormal, ), @@ -2202,8 +2142,7 @@ class _MarkingPapersState extends ConsumerState eventFireSub(model: SwitchKeyboardToReloadImages(true)); }); ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false); - ToastUtils.showSuccess(newOpenAuxiliary ? '开启双栏打分' : '关闭双栏打分', - duration: const Duration(milliseconds: 300)); + ToastUtils.showSuccess(newOpenAuxiliary ? '开启双栏打分' : '关闭双栏打分', duration: const Duration(milliseconds: 300)); }); }, // 触发总线事件 @@ -2212,8 +2151,7 @@ class _MarkingPapersState extends ConsumerState width: isBroadwise ? 18.w : 42.w, alignment: Alignment.center, decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topLeft: Radius.circular(8.w), bottomLeft: Radius.circular(8.w)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(8.w), bottomLeft: Radius.circular(8.w)), color: Theme.of(context).primaryColor, ), child: Row( @@ -2247,8 +2185,7 @@ class _MarkingPapersState extends ConsumerState tabName: _currentTab?.questionNum ?? '', tabs: _currentTabs, direction: keyboardModel?.screenDirection ?? ScreenDirection.HORIZONTAL_SCREEN, - call: (int detailId, String selectedQuesiontNum) => - refresh(theId: detailId, theQuestionNum: selectedQuesiontNum), + call: (int detailId, String selectedQuesiontNum) => refresh(theId: detailId, theQuestionNum: selectedQuesiontNum), markingUserId: widget.markingUserId, questionNum: _currentTab?.questionNum, ), @@ -2429,10 +2366,8 @@ Widget $abnormalBox( child: TextField( controller: controller, textInputAction: TextInputAction.next, - onEditingComplete: () => easyThrottle( - 'Abnormal_submission_confirmation_button', - () => _useAbnormal.submit(context, controller, - (reasonType, reason) => businessHandle(true, reasonType, reason))), + onEditingComplete: () => easyThrottle('Abnormal_submission_confirmation_button', + () => _useAbnormal.submit(context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason))), maxLines: 15, keyboardType: TextInputType.multiline, decoration: InputDecoration( @@ -2452,8 +2387,7 @@ Widget $abnormalBox( mainAxisAlignment: MainAxisAlignment.center, children: [ InkWell( - onTap: () => easyThrottle( - 'Abnormal_submission_confirmation_button', () => businessHandle(false, null, null)), + onTap: () => easyThrottle('Abnormal_submission_confirmation_button', () => businessHandle(false, null, null)), child: Container( padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), margin: EdgeInsets.only(right: 16.w), @@ -2483,8 +2417,7 @@ Widget $abnormalBox( InkWell( onTap: () => easyThrottle( 'Abnormal_submission_confirmation_button', - () => _useAbnormal.submit( - context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason)), + () => _useAbnormal.submit(context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason)), ), // () { @@ -2582,8 +2515,7 @@ class StandardAnswerRegion extends StatelessWidget { /// 异常题提交异常信息 @hwidget -Widget $abnormalQuestionInfo( - {required bool hasSubtopic, required bool isBroadwise, required bool show, double? score, ExceptionInfo? info}) { +Widget $abnormalQuestionInfo({required bool hasSubtopic, required bool isBroadwise, required bool show, double? score, ExceptionInfo? info}) { final _useFlagAnimation = useState(true); AnimationController _useAnimationHorizontal = useAnimationController( initialValue: 300, @@ -2675,14 +2607,12 @@ Widget $abnormalQuestionInfo( Row( children: [ if ((info?.studentName.length ?? 0) > 0) - quickText('考生:${info!.studentName}', - color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp + quickText('考生:${info!.studentName}', color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp // overflow: TextOverflow.clip, ), SizedBox(width: 3.w), if ((info?.studentExamNum.length ?? 0) > 0) - quickText('考号:${info!.studentExamNum}', - color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp + quickText('考号:${info!.studentExamNum}', color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp // overflow: TextOverflow.clip, ), ], @@ -2716,8 +2646,7 @@ Widget $abnormalQuestionInfo( /// 冲裁题仲裁历史得分信息 @hwidget -Widget $arbitrationQuestionInfo( - {required bool show, required bool isBroadwise, required bool hasSubtopic, required List data}) { +Widget $arbitrationQuestionInfo({required bool show, required bool isBroadwise, required bool hasSubtopic, required List data}) { final _useFlagAnimation = useState(true); AnimationController _useAnimationHorizontal = useAnimationController( initialValue: 300, From eb65701324942daac7793d25ba7e1b5eca5c7aa6 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Tue, 7 May 2024 19:25:16 +0800 Subject: [PATCH 02/15] no message --- .../lib/components/PictureOverview.dart | 337 +++++++++--------- marking_app/lib/pages/marking/do_papers.dart | 2 +- .../provider/draw_marking_provider.dart | 29 ++ 3 files changed, 208 insertions(+), 160 deletions(-) create mode 100644 marking_app/lib/pages/marking/provider/draw_marking_provider.dart 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); +} From 060ac01fde673b4d4b5f8108369e33a543eb57f7 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 8 May 2024 16:52:04 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E4=BB=BB=E5=8A=A1=EF=BC=8C=E8=BF=98=E5=89=A9?= =?UTF-8?q?=E4=B8=8B=E6=94=BE=E5=A4=A7=E5=90=8E=E6=89=B9=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enum/review_marks_bottom_btns_enum.dart | 6 + .../bottom_annotation_switch_cleanall.dart | 19 +- .../lib/components/PictureOverview.dart | 94 +++--- .../marking/bottom_annotation_switch.dart | 298 ------------------ marking_app/lib/pages/mainPage.dart | 1 + .../do_paper_bottom_review_marks.dart | 98 ++++++ marking_app/lib/pages/marking/do_papers.dart | 17 +- ...do_paper_bottom_review_marks_provider.dart | 13 + .../provider/draw_marking_provider.dart | 10 +- 9 files changed, 196 insertions(+), 360 deletions(-) create mode 100644 marking_app/lib/common/model/enum/review_marks_bottom_btns_enum.dart delete mode 100644 marking_app/lib/components/marking/bottom_annotation_switch.dart create mode 100644 marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart create mode 100644 marking_app/lib/pages/marking/provider/do_paper_bottom_review_marks_provider.dart diff --git a/marking_app/lib/common/model/enum/review_marks_bottom_btns_enum.dart b/marking_app/lib/common/model/enum/review_marks_bottom_btns_enum.dart new file mode 100644 index 0000000..5698a07 --- /dev/null +++ b/marking_app/lib/common/model/enum/review_marks_bottom_btns_enum.dart @@ -0,0 +1,6 @@ +enum ReviewMarksBottomBtnsEnum { + DRAG, // 拖动 + HANDWRITING, // 笔迹 + RETURN_PREVIOUS_LEVEL, // 返回上一级 + CLEAR_ALL // 清空全部 +} diff --git a/marking_app/lib/common/model/event_bus/bottom_annotation_switch_cleanall.dart b/marking_app/lib/common/model/event_bus/bottom_annotation_switch_cleanall.dart index 89e53ca..fec4a61 100644 --- a/marking_app/lib/common/model/event_bus/bottom_annotation_switch_cleanall.dart +++ b/marking_app/lib/common/model/event_bus/bottom_annotation_switch_cleanall.dart @@ -15,8 +15,23 @@ class BottomAnnotationSwitchCleanall extends Object { BottomAnnotationSwitchCleanall({this.cleanAll = false, this.previousStep = false, this.uploadImage = false}); - factory BottomAnnotationSwitchCleanall.fromJson(Map srcJson) => - _$BottomAnnotationSwitchCleanallFromJson(srcJson); + factory BottomAnnotationSwitchCleanall.fromJson(Map srcJson) => _$BottomAnnotationSwitchCleanallFromJson(srcJson); Map toJson() => _$BottomAnnotationSwitchCleanallToJson(this); } + +@JsonSerializable() +class BottomAnnotationSwitchCleanallOfMarking extends Object { + @JsonKey(name: 'cleanAll') + bool cleanAll; + + @JsonKey(name: 'previousStep') + bool previousStep; + + BottomAnnotationSwitchCleanallOfMarking({this.cleanAll = false, this.previousStep = false}); + + factory BottomAnnotationSwitchCleanallOfMarking.fromJson(Map srcJson) => + _$BottomAnnotationSwitchCleanallOfMarkingFromJson(srcJson); + + Map toJson() => _$BottomAnnotationSwitchCleanallOfMarkingToJson(this); +} diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index e7cc533..cbb2a97 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -22,6 +22,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/common/upload_img_secret_key.dart'; +import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart'; import 'package:marking_app/common/model/event_bus/bottom_annotation_switch_cleanall.dart'; import 'package:marking_app/common/model/job/test_questions_image_info.dart'; import 'package:marking_app/common/model/job/upload_file_interface_config.dart'; @@ -33,6 +34,7 @@ import 'package:marking_app/common/model/marking/switch_keyboard_to_reload_image import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/pages/homework_correction/hooks/use_cached_img_refresh.dart'; import 'package:marking_app/pages/marking/hooks/use_zoom_image_history.dart'; +import 'package:marking_app/pages/marking/provider/do_paper_bottom_review_marks_provider.dart'; import 'package:marking_app/pages/marking/provider/zoom_height_provider.dart'; import 'package:marking_app/pages/marking/provider/zoom_history_provider.dart'; import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart'; @@ -313,11 +315,12 @@ class PictureOverviewState extends ConsumerState with CommonMix _imageStream = imageWidget.image.resolve(ImageConfiguration())..addListener(_imageStreamListener!); } + var btnEnum = ref.watch(doPaperBottomReviewMarksProvider); // return imageWidget; return Listener( behavior: HitTestBehavior.opaque, onPointerMove: (PointerMoveEvent details) { - return; + if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return; if (globalPosition != null) { // 预防双指同时作用于屏幕 double dx = globalPosition!.dx; @@ -328,10 +331,19 @@ class PictureOverviewState extends ConsumerState with CommonMix if ((dxNew - dx).abs() > 22 || (dyNew - dy).abs() > 22) return; } globalPosition = details.localPosition; + Offset localPosition = globalPosition!; + + if (imagInfoModel != null && + (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { + // 笔迹画出图片区域 直接断笔 + var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); + return; + } // 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!); // } @@ -343,7 +355,7 @@ class PictureOverviewState extends ConsumerState with CommonMix } if (zoomOffset != null) { - // localPosition = Offset(localPosition.dx - (zoomOffset?.dx ?? 0), localPosition.dy); + localPosition = Offset(details.position.dx, localPosition.dy); } print('移动位置 zoomOffset==>dx:${zoomOffset?.dx}'); @@ -356,14 +368,15 @@ class PictureOverviewState extends ConsumerState with CommonMix 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)); + var newVal1 = ref.read(drawMarkingProvider).offsets..add(localPosition); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); }, onPointerDown: (PointerDownEvent event) { print('手指按下....${event.pointer}'); }, onPointerUp: (PointerUpEvent details) { print('离开.............'); - return; + if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return; globalPosition = null; // if (graffitiSwitch.openBrush || graffitiSwitch.openEraser) { // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); @@ -371,25 +384,29 @@ class PictureOverviewState extends ConsumerState with CommonMix // } var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); - ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); + var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); }, - 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)), + child: IgnorePointer( + ignoring: btnEnum != ReviewMarksBottomBtnsEnum.DRAG, + 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, ), - maxZoomWidth: containerWidth, - canvasColor: Colors.transparent, - backgroundColor: Colors.transparent, - maxZoomHeight: imagInfoModel?.scaleHeight, - initScale: initScale ?? 1, - initPosition: zoomOffset, - onScaleUpdate: onScaleUpdate, - onPositionUpdate: onPanUpPosition, ), ); }, @@ -420,21 +437,24 @@ class ExamPaperDrawing extends StatefulHookConsumerWidget { _ExamPaperDrawingState createState() => _ExamPaperDrawingState(); } -class _ExamPaperDrawingState extends ConsumerState with EventBusMixin { +class _ExamPaperDrawingState extends ConsumerState with EventBusMixin { // 用于记录手指位置的变量 late RemoveListener removeListener; late ValueNotifier> _vnHandWritings; - late List pointsPureData = []; + late List pointsPureData = []; @override void initState() { _vnHandWritings = ValueNotifier>([]); - removeListener = ref.read(drawMarkingProvider.notifier).addListener((state) => _vnHandWritings.value = [...state.data], fireImmediately: false); + removeListener = ref.read(drawMarkingProvider.notifier).addListener((state) { + pointsPureData = state.offsets; + _vnHandWritings.value = [...state.data]; + }, fireImmediately: false); // 事件总线监听 - eventOn(callback: (BottomAnnotationSwitchCleanall item) { + eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) { if (item.previousStep) { - if (_vnHandWritings.value.isEmpty) { + if (ref.read(drawMarkingProvider).data.isEmpty) { ToastUtils.showInfo('批注已清空'); return; } @@ -443,14 +463,13 @@ class _ExamPaperDrawingState extends ConsumerState with EventB if (index + 1 == pointsPureData.length) { pointsPureData = pointsPureData.sublist(0, index); - ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index))); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index), pointsPureData)); index = pointsPureData.toList().lastIndexOf(null); index == -1 ? -1 : index + 1; } if (index != -1) { pointsPureData = pointsPureData.sublist(0, index); - _vnHandWritings.value = _vnHandWritings.value.sublist(0, index); - ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index))); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index), pointsPureData)); } else { item.cleanAll = true; } @@ -461,20 +480,7 @@ class _ExamPaperDrawingState extends ConsumerState with EventB if (item.cleanAll) { pointsPureData.clear(); - _vnHandWritings.value.clear(); - } - - if (item.uploadImage) { - // 图片确认按钮,生成 - if (pointsPureData.isEmpty) { - ToastUtils.showInfo('请先批注再提交'); - return; - } - // _saveImage().then((FileResult? res) { - // if (res != null) { - // widget.imageCall(res.url!); - // } - // }); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], [])); } }); super.initState(); diff --git a/marking_app/lib/components/marking/bottom_annotation_switch.dart b/marking_app/lib/components/marking/bottom_annotation_switch.dart deleted file mode 100644 index 607722f..0000000 --- a/marking_app/lib/components/marking/bottom_annotation_switch.dart +++ /dev/null @@ -1,298 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:marking_app/common/model/enum/KeyboardType.dart'; -import 'package:marking_app/common/model/event_bus/bottom_annotation_switch_cleanall.dart'; -import 'package:marking_app/common/model/marking/annotation_graffiti_switch.dart'; -import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart'; -import 'package:marking_app/pages/common/event_bus_mixin.dart'; -import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart'; -import 'package:marking_app/provider/do_marking_provider.dart'; -import 'package:marking_app/utils/index.dart'; - -/** - * 底部批注开关 - */ -class BottomAnnotationSwitch extends StatefulHookConsumerWidget { - final double? maxWidth; - final bool homework; - const BottomAnnotationSwitch({this.maxWidth, this.homework = false, Key? key}) : super(key: key); - - @override - _BottomAnnotationSwitchState createState() => _BottomAnnotationSwitchState(); -} - -class _BottomAnnotationSwitchState extends ConsumerState - with SingleTickerProviderStateMixin, EventBusMixin { - late RemoveListener _annotationsListener; // 批注关闭监听 - late AnimationController _animationController; // 动画 - late AnnotationGraffitiSwitch graffitiSwitch; - late DoMarkingKeyboardModel _preferenceModel; - late double upperBound; - late double lowerBound; - Color? bgc; - bool isIos = false; - - @override - void initState() { - if (Platform.isIOS) { - toPrint(val: 'IOS'); - isIos = true; - } else if (Platform.isAndroid) { - toPrint(val: '安卓'); - } - var graffitiHander = ref.read(annotationGraffitiSwitchProvider.notifier); - if (widget.homework) { - setTimeOut(500, () { - graffitiHander.setSwitch(true); - if (!graffitiHander.state.openBrush) graffitiHander.setSwitchBrush(); - }); // 默认打开可以书写 - } - - _preferenceModel = ref.read(markingKeyboardProvider.notifier).state; // 偏好设置 - bool isVertical = _preferenceModel.screenDirection == ScreenDirection.VERTICAL_SCREEN; // 是否是垂直方向 - - switch (_preferenceModel.keyboard) { - case KeyboardType.RIGHT_SELECTION: - double isVerticalNumber = 58.w; - double noVerticalNumber = 28.w; - if (isIos) { - noVerticalNumber = 50.w; - } - upperBound = ScreenUtil().screenWidth - (isVertical ? isVerticalNumber : noVerticalNumber); - lowerBound = isVertical ? 34.w : 18.w; - break; - case KeyboardType.INPUT_TYPE: - // 输入型键盘不存在竖屏 - upperBound = ScreenUtil().screenWidth - (isIos ? 115.w : 95.w); - lowerBound = 18.w; - - break; - case KeyboardType.BOTTOM_SELECTION: - upperBound = ScreenUtil().screenWidth; - lowerBound = isVertical ? 34.w : 18.w; - - break; - } - - upperBound = widget.maxWidth ?? upperBound; - _animationController = AnimationController( - value: graffitiHander.state.annotationSwitch ? upperBound : lowerBound, // 设置默认值 - duration: const Duration(milliseconds: 300), - lowerBound: lowerBound, - upperBound: upperBound, - vsync: this, - )..addListener(toUp); - - _annotationsListener = graffitiHander.addListener((state) { - graffitiSwitch = state; - if (state.annotationSwitch) { - bgc = const Color.fromRGBO(51, 57, 62, 1); - // toUp(); - _animationController.forward(); - } else { - _animationController.reverse(); - setTimeOut(300, () => bgc = null); - } - }); - - super.initState(); - } - - @override - void dispose() { - _annotationsListener(); - _animationController - ..removeListener(toUp) - ..dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - ScreenDirection _screenDirection = _preferenceModel.screenDirection; - bool isVertical = _screenDirection == ScreenDirection.VERTICAL_SCREEN; // 是否是垂直 - - // print('当前屏幕情况:${graffitiSwitch.openBrush}'); - // print(isVertical); - - AnnotationGraffitiSwitch _graffitiSwitch = ref.watch(annotationGraffitiSwitchProvider); - - double barrierSize = ScreenUtil().screenWidth / (isVertical ? 20 : 6); - Color actionColor = Colors.white; - Color defaultColor = Color.fromRGBO(132, 146, 163, 1); - return OrientationBuilder( - builder: (BuildContext context, Orientation orientation) { - bool isVertical = orientation == Orientation.portrait; - - double iconSize = (isVertical ? 32 : 28).sp; - return Container( - height: 52.h, - // width: widget.homework ? double.infinity : _animationController.value, - width: _animationController.value, - color: widget.homework ? Color.fromRGBO(51, 57, 62, 0.2) : bgc, - padding: EdgeInsets.symmetric(vertical: 1.h), - child: widget.homework - ? Row( - children: [ - SizedBox(width: barrierSize + 20.w), - InkWell( - onTap: () { - easyThrottle('setSwitchBrush', - () => ref.read(annotationGraffitiSwitchProvider.notifier).setSwitchBrush()); - }, - child: Icon(const IconData(0xe623, fontFamily: "AlibabaIcon"), - size: iconSize, color: _graffitiSwitch.openBrush ? actionColor : defaultColor), - ), - SizedBox(width: 24.w), - InkWell( - onTap: () { - eventFire(model: BottomAnnotationSwitchCleanall(previousStep: true)); - }, - child: Icon(IconData(0xe61d, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), - ), - const Expanded(child: SizedBox()), - InkWell( - onTap: () { - easyThrottle('setSwitchMagnifier', - () => ref.read(annotationGraffitiSwitchProvider.notifier).setMagnifier()); - }, - // IconData(0xe62f, fontFamily: "AlibabaIcon") - child: Icon(IconData(0xe634, fontFamily: "AlibabaIcon"), - size: iconSize, color: _graffitiSwitch.magnifier ? actionColor : defaultColor), - ), - SizedBox(width: 24.w), - InkWell( - onTap: () { - eventFire(model: BottomAnnotationSwitchCleanall(cleanAll: true)); - }, - child: Icon(IconData(0xe61f, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), - ), - SizedBox(width: 24.w), - InkWell( - onTap: () { - easyThrottle( - 'setSwitchMagnifier', - () => ref.read(annotationGraffitiSwitchProvider.notifier).setTrajectory(), - ); - }, - child: Icon( - IconData(0xe629, fontFamily: "AlibabaIcon"), - size: iconSize, - color: _graffitiSwitch.trajectoryDisplay ? actionColor : defaultColor, - ), - ), - SizedBox(width: isIos ? 40.w : 50.w), - ], - ) - : Stack( - alignment: const FractionalOffset(0, 0.5), - children: [ - if (bgc != null) - Row( - children: [ - SizedBox(width: barrierSize + 20.w), - InkWell( - onTap: () { - easyThrottle('setSwitchBrush', - () => ref.read(annotationGraffitiSwitchProvider.notifier).setSwitchBrush()); - }, - child: Icon(const IconData(0xe623, fontFamily: "AlibabaIcon"), - size: iconSize, color: _graffitiSwitch.openBrush ? actionColor : defaultColor), - ), - SizedBox(width: 24.w), - InkWell( - onTap: () { - eventFire(model: BottomAnnotationSwitchCleanall(previousStep: true)); - }, - child: - Icon(IconData(0xe61d, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), - ), - - // 不需要橡皮擦 - // InkWell( - // onTap: () { - // easyThrottle( - // 'setSwitchEraser', () => ref.read(annotationGraffitiSwitchProvider.notifier).setSwitchEraser()); - // }, - // child: Icon(const IconData(0xe61c, fontFamily: "AlibabaIcon"), - // color: _graffitiSwitch.openEraser ? Theme.of(context).primaryColor : Colors.white), - // ), - const Expanded(child: SizedBox()), - InkWell( - onTap: () { - easyThrottle('setSwitchMagnifier', - () => ref.read(annotationGraffitiSwitchProvider.notifier).setMagnifier()); - }, - child: Icon(IconData(0xe62f, fontFamily: "AlibabaIcon"), - size: iconSize, color: _graffitiSwitch.magnifier ? actionColor : defaultColor), - ), - SizedBox(width: 24.w), - InkWell( - onTap: () { - eventFire(model: BottomAnnotationSwitchCleanall(cleanAll: true)); - }, - child: - Icon(IconData(0xe61f, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), - ), - // SizedBox(width: 24.w), - // InkWell( - // onTap: (){ - // eventFire(model:BottomAnnotationSwitchCleanall(uploadImage: true)); - // }, - // child: Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Icon(const IconData(0xe614, fontFamily: "AlibabaIcon"), color: Colors.white,size: 22.sp,), - // quickText('提交批注',color: Colors.white,size: 9.sp), - // ], - // ) - // ), - - SizedBox(width: isIos ? 40.w : 26.w), - ], - ), - InkWell( - onTap: () { - easyThrottle('setSwitchMarkingGraffiti', () { - if ([upperBound, lowerBound].contains(_animationController.value)) { - ref - .read(annotationGraffitiSwitchProvider.notifier) - .setSwitch(!graffitiSwitch.annotationSwitch); - } - }); - }, - child: Container( - // width: isVertical ? 34.w : 16.w, - width: barrierSize, - padding: EdgeInsets.only(top: 4.h, bottom: 4.h, right: 3.w), - alignment: Alignment.centerRight, - decoration: BoxDecoration( - color: const Color.fromRGBO(253, 147, 21, 1), - borderRadius: BorderRadius.only( - topRight: Radius.circular(30.sp), - bottomRight: Radius.circular(30.sp), - ), - ), - child: Icon( - !graffitiSwitch.annotationSwitch - ? const IconData(0xe622, fontFamily: "AlibabaIcon") - : const IconData(0xe621, fontFamily: "AlibabaIcon"), - color: Colors.white, - size: isVertical ? 20.sp : 26.sp, - ), - ), - ) - ], - ), - ); - }, - ); - } - - void toUp() { - toUpState(setState, () {}, mounted); - } -} diff --git a/marking_app/lib/pages/mainPage.dart b/marking_app/lib/pages/mainPage.dart index a073354..8c76648 100644 --- a/marking_app/lib/pages/mainPage.dart +++ b/marking_app/lib/pages/mainPage.dart @@ -104,6 +104,7 @@ class TheMainPageState extends ConsumerState with CommonMixin { } void getAppUpgrade(UserInfo user) async { + if (!bool.fromEnvironment('dart.vm.product')) return; try { showUpgrade = true; if (['18888888888'].contains(user.loginName)) return; diff --git a/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart b/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart new file mode 100644 index 0000000..3185981 --- /dev/null +++ b/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart'; +import 'package:marking_app/common/model/event_bus/bottom_annotation_switch_cleanall.dart'; +import 'package:marking_app/pages/common/event_bus_mixin.dart'; +import 'package:marking_app/utils/anti_shake_throttling.dart'; + +import '../provider/do_paper_bottom_review_marks_provider.dart'; + +// 底部批阅动作切换区域 +class DoPaperBottomReviewMarks extends StatefulHookConsumerWidget { + const DoPaperBottomReviewMarks({super.key}); + + @override + ConsumerState createState() => _DoPaperBottomReviewMarksState(); +} + +class _DoPaperBottomReviewMarksState extends ConsumerState with EventBusMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + eventCancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + var btnEnum = ref.watch(doPaperBottomReviewMarksProvider); + Color actionColor = Theme.of(context).primaryColor.withOpacity(0.9); + return Positioned( + left: 3.w, + bottom: 6.h, + child: AbsorbPointer( + absorbing: false, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.r), + color: const Color.fromRGBO(24, 32, 32, 0.1), + ), + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 拖动 + IconButton( + onPressed: () => easyThrottle( + 'REVIEW_MARKS_BOTTOM_BTNS', + () => ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG), + ), + padding: EdgeInsets.zero, + icon: Icon(Icons.back_hand_outlined, color: btnEnum == ReviewMarksBottomBtnsEnum.DRAG ? actionColor : Colors.white, size: 34.r), + ), + SizedBox(width: 4.w), + // 批阅笔迹 + IconButton( + onPressed: () => easyThrottle( + 'REVIEW_MARKS_BOTTOM_BTNS', + () => ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.HANDWRITING), + ), + padding: EdgeInsets.zero, + icon: Icon(Icons.create_outlined, color: btnEnum == ReviewMarksBottomBtnsEnum.HANDWRITING ? actionColor : Colors.white, size: 34.r), + ), + SizedBox(width: 4.w), + // 批阅痕迹 ==> 返回上一级 + IconButton( + onPressed: () => easyThrottle( + 'REVIEW_MARKS_BOTTOM_BTNS', + duration: const Duration(milliseconds: 100), + () => eventFire(model: BottomAnnotationSwitchCleanallOfMarking(previousStep: true)), + ), + padding: EdgeInsets.zero, + icon: Icon(Icons.reply_outlined, + color: btnEnum == ReviewMarksBottomBtnsEnum.RETURN_PREVIOUS_LEVEL ? actionColor : Colors.white, size: 34.r), + ), + SizedBox(width: 4.w), + // 批阅痕迹 ==> 清空 + IconButton( + onPressed: () => easyThrottle( + 'REVIEW_MARKS_BOTTOM_BTNS', + duration: const Duration(milliseconds: 100), + () => eventFire(model: BottomAnnotationSwitchCleanallOfMarking(cleanAll: true)), + ), + padding: EdgeInsets.zero, + icon: Icon(Icons.reply_all_outlined, color: btnEnum == ReviewMarksBottomBtnsEnum.CLEAR_ALL ? actionColor : Colors.white, size: 34.r), + ), + ], + ), + ), + ), + ); + } +} diff --git a/marking_app/lib/pages/marking/do_papers.dart b/marking_app/lib/pages/marking/do_papers.dart index f1738e2..953b02e 100644 --- a/marking_app/lib/pages/marking/do_papers.dart +++ b/marking_app/lib/pages/marking/do_papers.dart @@ -44,7 +44,6 @@ import 'package:marking_app/common/model/marking/submit_exam_small_params.dart'; import 'package:marking_app/common/model/marking/switch_keyboard_to_reload_images.dart'; import 'package:marking_app/components/PictureOverview.dart'; -import 'package:marking_app/components/marking/bottom_annotation_switch.dart'; import 'package:marking_app/components/marking/marking_keyboard_switch.dart'; import 'package:marking_app/components/marking/marking_question_type_drawer.dart'; import 'package:marking_app/components/marking/marking_seting.dart'; @@ -67,6 +66,7 @@ import 'package:marking_app/utils/request/rest_client.dart'; import 'package:percent_indicator/percent_indicator.dart'; import 'package:wakelock/wakelock.dart'; +import 'components/do_paper_bottom_review_marks.dart'; import 'hooks/use_abnormal.dart'; part 'do_papers.g.dart'; @@ -1930,18 +1930,7 @@ class _MarkingPapersState extends ConsumerState imageItems: data.getImageData(), ), ), - // 批注开关 暂时注释 TODO - // if (!showSetingFlag && - // !widget.exceptional && - // currentQuestion != null && - // annotationsFlag && - // !showAbnormal && - // !showStandardAnswer) - // Positioned( - // left: 0, - // bottom: 0, - // child: BottomAnnotationSwitch(maxWidth: ScreenUtil().screenWidth - 1.5.w), - // ), + // 大题评分展示框 if (!hasSubtopic) Positioned( @@ -2009,6 +1998,8 @@ class _MarkingPapersState extends ConsumerState heroTag: 'other', ), ), + // 底部批阅痕迹按钮 + DoPaperBottomReviewMarks(), // 下一题 按钮 if (!_theOldAnnotationGraffiti && pressedNextTest != null && isNormal) Positioned( diff --git a/marking_app/lib/pages/marking/provider/do_paper_bottom_review_marks_provider.dart b/marking_app/lib/pages/marking/provider/do_paper_bottom_review_marks_provider.dart new file mode 100644 index 0000000..60109f0 --- /dev/null +++ b/marking_app/lib/pages/marking/provider/do_paper_bottom_review_marks_provider.dart @@ -0,0 +1,13 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart'; + +// 底部按钮同步数据 +final doPaperBottomReviewMarksProvider = StateNotifierProvider( + (ref) => DoPaperBottomReviewMarksHandle(ReviewMarksBottomBtnsEnum.DRAG), +); + +class DoPaperBottomReviewMarksHandle extends StateNotifier { + DoPaperBottomReviewMarksHandle(ReviewMarksBottomBtnsEnum val) : super(val); + + void setState(ReviewMarksBottomBtnsEnum val) => state = val; +} diff --git a/marking_app/lib/pages/marking/provider/draw_marking_provider.dart b/marking_app/lib/pages/marking/provider/draw_marking_provider.dart index e1f8239..fdf95be 100644 --- a/marking_app/lib/pages/marking/provider/draw_marking_provider.dart +++ b/marking_app/lib/pages/marking/provider/draw_marking_provider.dart @@ -7,12 +7,15 @@ * @Description: APP上传文件状态 */ +import 'dart:ui'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../../components/PictureOverview.dart'; -// 评分进度还是批阅进度 -final drawMarkingProvider = StateNotifierProvider((ref) => DrawMarkingProviderHandle(DrawMarkingVal([]))); +// 批阅痕迹同步 +final drawMarkingProvider = + StateNotifierProvider((ref) => DrawMarkingProviderHandle(DrawMarkingVal([], []))); class DrawMarkingProviderHandle extends StateNotifier { DrawMarkingProviderHandle(DrawMarkingVal val) : super(val); @@ -24,6 +27,7 @@ class DrawMarkingProviderHandle extends StateNotifier { class DrawMarkingVal { List data; + List offsets; - DrawMarkingVal(this.data); + DrawMarkingVal(this.data, this.offsets); } From a13cab2c9625a3ceaeab55e63970acb47edf082f Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 9 May 2024 19:55:25 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/job/test_questions_image_info.dart | 19 +++-- .../lib/components/PictureOverview.dart | 85 ++++++++++++++----- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/marking_app/lib/common/model/job/test_questions_image_info.dart b/marking_app/lib/common/model/job/test_questions_image_info.dart index e9a1e7c..23539ea 100644 --- a/marking_app/lib/common/model/job/test_questions_image_info.dart +++ b/marking_app/lib/common/model/job/test_questions_image_info.dart @@ -35,8 +35,17 @@ class TestQuestionsImageInfo extends Object { double? imageHeightOffsetend; - TestQuestionsImageInfo( - {required this.width, required this.height, required this.url, required this.boxWidth, required this.boxHeight, this.pixelRatio = 1}) { + double zoom; // 图片放大比例 + + TestQuestionsImageInfo({ + required this.width, + required this.height, + required this.url, + required this.boxWidth, + required this.boxHeight, + this.pixelRatio = 1, + this.zoom = 1, + }) { // print('图片宽度:$width'); // print('图片高度:$height'); @@ -46,11 +55,11 @@ class TestQuestionsImageInfo extends Object { pixelRatio = width / boxWidth; scale = boxWidth / width; - scaleHeight = scale! * height; - scaleWidth = scale! * width; + scaleHeight = scale! * height * zoom; + scaleWidth = scale! * width * zoom; if (scaleHeight != null) { - imageHeightOffsetStart = (boxHeight - scaleHeight!) / 2; + imageHeightOffsetStart = boxHeight <= scaleHeight! ? 0 : (boxHeight - scaleHeight!) / 2; imageHeightOffsetend = imageHeightOffsetStart! + scaleHeight!; } } diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index cbb2a97..19aab63 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -106,6 +106,8 @@ class PictureOverviewState extends ConsumerState with CommonMix // 用于记录绘图结果的变量 Offset? globalPosition; // 是否正在绘制 MarkingHistoryZoomInfo? zoomInfo; + bool illegalArea = false; // 非法区域(批阅笔迹不在试题图片中) + final GlobalKey _zoomKey = GlobalKey>(); @override void initState() { @@ -141,7 +143,7 @@ class PictureOverviewState extends ConsumerState with CommonMix bool flieExist = temFile!.existsSync(); if (flieExist) temFile!.delete(); } - if (zoomOffset != null) saveZoomPosition(); + // if (zoomOffset != null) saveZoomPosition(); } catch (e) {} super.dispose(); } @@ -230,6 +232,7 @@ class PictureOverviewState extends ConsumerState with CommonMix } void onPanUpPosition(Offset val) async { + // 手指在移动 非物体移动的位置 print('**************** 正在移动位置 YYY:${val.dy}'); print('**************** 正在移动位置 XXX:${val.dx}'); zoomOffset = val; @@ -251,14 +254,17 @@ class PictureOverviewState extends ConsumerState with CommonMix markingUserId: widget.markingUserId, ); zoomInfo = info; + if (double.parse(zoom.toStringAsFixed(2)) <= 1) zoom = 1; if (imagInfoModel != null) { + // 根据缩放比例重置被放大的图片的尺寸 imagInfoModel = TestQuestionsImageInfo( // 获取图片的宽高 boxHeight: imagInfoModel!.boxHeight, boxWidth: imagInfoModel!.boxWidth, url: imagInfoModel!.url, - height: imagInfoModel!.height * zoom, - width: imagInfoModel!.width * zoom, + height: imagInfoModel!.height, + width: imagInfoModel!.width, + zoom: zoom, ); } FastData.getInstance().setMarkingZoomInfo(info); @@ -333,39 +339,70 @@ class PictureOverviewState extends ConsumerState with CommonMix globalPosition = details.localPosition; Offset localPosition = globalPosition!; - if (imagInfoModel != null && - (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { - // 笔迹画出图片区域 直接断笔 - var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); - var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); - ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); - return; - } + print('绝对位置:X:${details.position.dx}; Y:${details.position.dy}'); + print('相对位置:X:${globalPosition!.dx}; Y:${globalPosition!.dy}'); + + // if (imagInfoModel != null && + // (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { + // // 笔迹画出图片区域 直接断笔 + // var dataVal = ref.read(drawMarkingProvider).data; + // if (dataVal.length - 1 > -1 && dataVal[dataVal.length - 1].data != null) { + // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + // var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); + // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); + // } + // illegalArea = true; + // return; + // } + // illegalArea = false; // Offset localPosition = (context.findRenderObject() as RenderBox).globalToLocal(details.localPosition); // if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { // if (imagInfoModel?.scaleHeight != null) { // localPosition = Offset(localPosition.dx, localPosition.dy - imagInfoModel!.scaleHeight!); // } + var zoomState = _zoomKey.currentState; + if (zoomState != null) { + print(zoomState); + } double remainingHeight = imagInfoModel!.imageHeightOffsetStart!; // 剩余高度 var _scaleY = (zoomInfo?.scale ?? 1); if (remainingHeight > 1) { localPosition = Offset(localPosition.dx, localPosition.dy - remainingHeight); + + // if (zoomOffset != null) { + // // var density = (imagInfoModel!.boxWidth / imagInfoModel!.scaleWidth!); + // localPosition = Offset(localPosition.dx/, localPosition.dy); + // } + } else { + if (zoomOffset != null) { + localPosition = Offset(localPosition.dx, localPosition.dy + zoomOffset!.dy.abs()); + } } - if (zoomOffset != null) { - localPosition = Offset(details.position.dx, localPosition.dy); + if (imagInfoModel?.zoom != null && imagInfoModel?.zoom != 1) { + // 计算视图被放大比例 还原笔迹坐标 + localPosition = Offset(localPosition.dx / imagInfoModel!.zoom, localPosition.dy / imagInfoModel!.zoom); + if (zoomOffset != null) { + // 如果滚动条有触动就加上滚动条滚动的位置 + var density = (imagInfoModel!.boxWidth / imagInfoModel!.scaleWidth!); + localPosition = Offset(localPosition.dx + zoomOffset!.dx.abs() / imagInfoModel!.zoom, localPosition.dy); + } } - print('移动位置 zoomOffset==>dx:${zoomOffset?.dx}'); - print('移动位置 zoomOffset==>dy:${zoomOffset?.dy}'); + // if (zoomInfo != null) { + // localPosition = Offset(details.position.dx, localPosition.dy); + // } - print('缩放的比例:${_scaleY}'); - print('原本的dy:${globalPosition?.dy}'); - print('原本的dx:${globalPosition?.dx}'); - print('本来的Y轴:${localPosition.dy}'); - print('还原后的Y轴:${localPosition.dy * _scaleY}'); + // 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)); var newVal1 = ref.read(drawMarkingProvider).offsets..add(localPosition); @@ -377,7 +414,10 @@ class PictureOverviewState extends ConsumerState with CommonMix onPointerUp: (PointerUpEvent details) { print('离开.............'); if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return; + globalPosition = null; + // 如果在空白区域 非试题图片区域就返回 + if (illegalArea) return; // if (graffitiSwitch.openBrush || graffitiSwitch.openEraser) { // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); @@ -390,6 +430,7 @@ class PictureOverviewState extends ConsumerState with CommonMix child: IgnorePointer( ignoring: btnEnum != ReviewMarksBottomBtnsEnum.DRAG, child: Zoom( + key: _zoomKey, // initTotalZoomOut: true, child: ExamPaperDrawing( key: examPaperDrawingKey, @@ -399,9 +440,9 @@ class PictureOverviewState extends ConsumerState with CommonMix decoration: const BoxDecoration(color: const Color.fromRGBO(249, 250, 254, 1)), ), maxZoomWidth: containerWidth, - canvasColor: Colors.transparent, + canvasColor: Colors.red, backgroundColor: Colors.transparent, - maxZoomHeight: imagInfoModel?.scaleHeight, + maxZoomHeight: imagInfoModel?.scaleHeight != null ? (imagInfoModel!.scaleHeight! / imagInfoModel!.zoom) : null, initScale: initScale ?? 1, initPosition: zoomOffset, onScaleUpdate: onScaleUpdate, From adc07a93469860ecb7a3835b579b4838e728ae38 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Fri, 10 May 2024 10:23:47 +0800 Subject: [PATCH 05/15] no message --- .../lib/components/PictureOverview.dart | 71 +++++-------------- 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 19aab63..2498ef7 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -281,7 +281,6 @@ class PictureOverviewState extends ConsumerState with CommonMix double containerWidth = constraints.maxWidth; double containerHeight = constraints.maxHeight; - print('LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL'); return $LocalAndNetworkSwitch( zoomGlobalKey: zoomGlobalKey, containerWidth: containerWidth, @@ -300,7 +299,6 @@ class PictureOverviewState extends ConsumerState with CommonMix print('更新需要上传的文件'); }, 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!); @@ -313,7 +311,6 @@ class PictureOverviewState extends ConsumerState with CommonMix height: info.image.height.toDouble(), width: info.image.width.toDouble(), ); - printJson(imagInfoModel!.toJson()); Future.delayed(Duration.zero, () { ref.read(zoomHeightProvider.notifier).setState(imagInfoModel?.scaleHeight ?? 0.0); }); @@ -339,35 +336,21 @@ class PictureOverviewState extends ConsumerState with CommonMix globalPosition = details.localPosition; Offset localPosition = globalPosition!; - print('绝对位置:X:${details.position.dx}; Y:${details.position.dy}'); - print('相对位置:X:${globalPosition!.dx}; Y:${globalPosition!.dy}'); - - // if (imagInfoModel != null && - // (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { - // // 笔迹画出图片区域 直接断笔 - // var dataVal = ref.read(drawMarkingProvider).data; - // if (dataVal.length - 1 > -1 && dataVal[dataVal.length - 1].data != null) { - // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); - // var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); - // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); - // } - // illegalArea = true; - // return; - // } - // illegalArea = false; - // Offset localPosition = (context.findRenderObject() as RenderBox).globalToLocal(details.localPosition); - // if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { - - // if (imagInfoModel?.scaleHeight != null) { - // localPosition = Offset(localPosition.dx, localPosition.dy - imagInfoModel!.scaleHeight!); - // } - var zoomState = _zoomKey.currentState; - if (zoomState != null) { - print(zoomState); + if (imagInfoModel != null && + (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { + // 笔迹画出图片区域 直接断笔 + var dataVal = ref.read(drawMarkingProvider).data; + if (dataVal.length - 1 > -1 && dataVal[dataVal.length - 1].data != null) { + var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); + } + illegalArea = true; + return; } + illegalArea = false; double remainingHeight = imagInfoModel!.imageHeightOffsetStart!; // 剩余高度 - var _scaleY = (zoomInfo?.scale ?? 1); if (remainingHeight > 1) { localPosition = Offset(localPosition.dx, localPosition.dy - remainingHeight); @@ -386,42 +369,22 @@ class PictureOverviewState extends ConsumerState with CommonMix localPosition = Offset(localPosition.dx / imagInfoModel!.zoom, localPosition.dy / imagInfoModel!.zoom); if (zoomOffset != null) { // 如果滚动条有触动就加上滚动条滚动的位置 - var density = (imagInfoModel!.boxWidth / imagInfoModel!.scaleWidth!); localPosition = Offset(localPosition.dx + zoomOffset!.dx.abs() / imagInfoModel!.zoom, localPosition.dy); } } - // if (zoomInfo != null) { - // localPosition = Offset(details.position.dx, 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)); var newVal1 = ref.read(drawMarkingProvider).offsets..add(localPosition); ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); }, - onPointerDown: (PointerDownEvent event) { - print('手指按下....${event.pointer}'); - }, + // onPointerDown: (PointerDownEvent event) { + // }, onPointerUp: (PointerUpEvent details) { - print('离开.............'); if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return; - - globalPosition = null; // 如果在空白区域 非试题图片区域就返回 if (illegalArea) return; - // if (graffitiSwitch.openBrush || graffitiSwitch.openEraser) { - // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); - // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); - // } + + globalPosition = null; var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); @@ -440,7 +403,7 @@ class PictureOverviewState extends ConsumerState with CommonMix decoration: const BoxDecoration(color: const Color.fromRGBO(249, 250, 254, 1)), ), maxZoomWidth: containerWidth, - canvasColor: Colors.red, + canvasColor: Colors.transparent, backgroundColor: Colors.transparent, maxZoomHeight: imagInfoModel?.scaleHeight != null ? (imagInfoModel!.scaleHeight! / imagInfoModel!.zoom) : null, initScale: initScale ?? 1, From ad660bec119e300419c3e4309c55428ca476e127 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Fri, 10 May 2024 19:26:59 +0800 Subject: [PATCH 06/15] no message --- .../model/marking/marking_text_question.dart | 34 ++++++------- .../lib/components/PictureOverview.dart | 50 ++++++++++++++++--- marking_app/lib/pages/marking/do_papers.dart | 23 ++++++--- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/marking_app/lib/common/model/marking/marking_text_question.dart b/marking_app/lib/common/model/marking/marking_text_question.dart index f206ab9..12adc1c 100644 --- a/marking_app/lib/common/model/marking/marking_text_question.dart +++ b/marking_app/lib/common/model/marking/marking_text_question.dart @@ -96,9 +96,9 @@ class MarkingTextQuestion extends Object { @JsonKey(name: 'papersUrlStr') List? papersUrlStr; - // 批注图片 预提交集合 - @JsonKey(name: 'commentImageUrlTodo') - List? commentImageUrlTodo; + // // 批注图片 预提交集合 + // @JsonKey(name: 'commentImageUrlTodo') + // List? commentImageUrlTodo; // 批注图片Map @JsonKey(name: 'commentImageUrlMap') @@ -115,8 +115,8 @@ class MarkingTextQuestion extends Object { @JsonKey(name: 'historicalScorings') List? historicalScorings; - MarkingTextQuestion(this.id, this.totalScore, this.isFinish, this.subQuestionDetailList, this.isException, - this.questionNum, this.score, this.studentAnswerList, + MarkingTextQuestion( + this.id, this.totalScore, this.isFinish, this.subQuestionDetailList, this.isException, this.questionNum, this.score, this.studentAnswerList, // this.questionIndex, {required this.commentImageUrl, required this.lastOne, @@ -130,7 +130,7 @@ class MarkingTextQuestion extends Object { // this.totalCount = 0, // this.currentIndex = 0, this.papersUrl = const [], - this.commentImageUrlTodo, + // this.commentImageUrlTodo, this.commentImageUrlMap = const {}}) { score = isFinish ? score : null; completeRating = isFinish && score != null; @@ -140,14 +140,20 @@ class MarkingTextQuestion extends Object { commentImageUrlMap = Map(); if (commentImageUrl.isNotEmpty) { - for (var element in commentImageUrl) { - commentImageUrlMap[element] = '$element?${DateTime.now().millisecondsSinceEpoch}'; + // for (var element in commentImageUrl) { + // commentImageUrlMap[element] = '$element?${DateTime.now().millisecondsSinceEpoch}'; + // } + for (var i = 0; i < commentImageUrl.length; i++) { + var element = commentImageUrl[i]; + var originalImage = studentAnswerList[i]; + commentImageUrlMap[originalImage] = '$element?${DateTime.now().millisecondsSinceEpoch}'; } } else { for (var element in studentAnswerList) { commentImageUrlMap[element] = element; } } + // if (historicalScore != null) { // this.historicalScorings = (jsonDecode(historicalScore!) as List).map((e) { // return HistoricalScoring.fromJson(e as Map); @@ -165,10 +171,6 @@ class MarkingTextQuestion extends Object { factory MarkingTextQuestion.fromJson(Map srcJson) => _$MarkingTextQuestionFromJson(srcJson); List getImageData() { - if (commentImageUrlTodo != null && commentImageUrlTodo!.isNotEmpty) { - return commentImageUrlTodo!; - } - if (commentImageUrl.isNotEmpty) { return commentImageUrl; } @@ -178,10 +180,8 @@ class MarkingTextQuestion extends Object { bool setImageList(String resImage, int imageIndex) { try { - commentImageUrlTodo ??= getImageData().map((e) => e).toList(); String oldImage = studentAnswerList[imageIndex]; commentImageUrlMap[oldImage] = '$resImage?${DateTime.now().millisecondsSinceEpoch}'; - commentImageUrlTodo![imageIndex] = resImage; return true; } catch (e) { return false; @@ -220,11 +220,7 @@ class SubQuestions extends Object { bool completeRating; SubQuestions( - {required this.subQuestionScore, - required this.subQuestionNum, - this.subQuestionGotScore, - required this.isFinish, - this.completeRating = false}) { + {required this.subQuestionScore, required this.subQuestionNum, this.subQuestionGotScore, required this.isFinish, this.completeRating = false}) { subQuestionGotScore = isFinish ? subQuestionGotScore : null; completeRating = isFinish && subQuestionGotScore != null; } diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 2498ef7..8c89dbb 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -30,6 +30,7 @@ import 'package:marking_app/common/model/job/upload_file_interface_config_params import 'package:marking_app/common/model/marking/annotation_graffiti_switch.dart'; import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart'; import 'package:marking_app/common/model/marking/marking_history_zoom_info.dart'; +import 'package:marking_app/common/model/marking/marking_text_question.dart'; import 'package:marking_app/common/model/marking/switch_keyboard_to_reload_images.dart'; import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/pages/homework_correction/hooks/use_cached_img_refresh.dart'; @@ -69,6 +70,7 @@ class PictureOverview extends StatefulHookConsumerWidget { final bool annotationsFlag; final String testQuestionNumber; final Map commentImageMap; + final MarkingTextQuestion data; const PictureOverview({ required this.imageItems, @@ -77,6 +79,7 @@ class PictureOverview extends StatefulHookConsumerWidget { required this.testQuestionNumber, required this.questionNum, required this.markingUserId, + required this.data, this.homework = false, this.imageScale = 1, this.imagePosition, @@ -87,7 +90,7 @@ class PictureOverview extends StatefulHookConsumerWidget { PictureOverviewState createState() => PictureOverviewState(); } -class PictureOverviewState extends ConsumerState with CommonMixin { +class PictureOverviewState extends ConsumerState with CommonMixin, EventBusMixin { final GlobalKey theglobalKey = GlobalKey(); final GlobalKey<_ExamPaperDrawingState> examPaperDrawingKey = GlobalKey<_ExamPaperDrawingState>(); final GlobalKey zoomGlobalKey = GlobalKey(); // zoom @@ -132,11 +135,39 @@ class PictureOverviewState extends ConsumerState with CommonMix graffitiSwitch = state; toUpState(setState, () {}, mounted); }); + + // 事件总线监听 清空数据 + eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) async { + if (ref.read(drawMarkingProvider).data.isEmpty) { + if (widget.data.commentImageUrl.isNotEmpty) { + bool? res = await showDialog( + // 表示点击灰色背景的时候是否消失弹出框 + barrierDismissible: false, + context: context, + builder: (context1) { + return AlertDialog(content: quickText("是否撤销上次批注痕迹"), actions: [ + TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)), + TextButton(child: quickText("确定", color: Theme.of(context).primaryColor), onPressed: () => Navigator.pop(context1, true)) + ]); + }, + ); + if (res == true) { + widget.data.commentImageUrl.removeAt(currentIndex); + var theUrl = widget.imageItems[currentIndex]; + widget.commentImageMap[theUrl] = theUrl; + toUpState(setState, () {}, mounted); + } + } else { + ToastUtils.showInfo('批注已清空'); + } + } + }); } @override void dispose() { _annotationsListener(); + eventCancel(); try { _imageStream?.removeListener(_imageStreamListener!); if (temFile != null) { @@ -156,9 +187,12 @@ class PictureOverviewState extends ConsumerState with CommonMix // 没有图片就上传图片 RenderRepaintBoundary? boundary = theglobalKey.currentContext!.findRenderObject() as RenderRepaintBoundary?; if (boundary == null) return null; - double dpr = MediaQuery.of(context).devicePixelRatio; - // double dpr = ui.window.devicePixelRatio; - ui.Image image = await boundary.toImage(pixelRatio: dpr); + // double dpr = MediaQuery.of(context).devicePixelRatio; + + double pixelRatio = MediaQuery.of(context).devicePixelRatio; + if (imagInfoModel?.pixelRatio != null) pixelRatio = imagInfoModel!.pixelRatio; + + ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); if (byteData == null) { /// 等于null 已经是异常了 @@ -172,8 +206,11 @@ class PictureOverviewState extends ConsumerState with CommonMix temFile = file; } - crypto.Digest fileMd5 = crypto.md5.convert(await temFile!.readAsBytes()); + if (imagInfoModel != null) { + // 剪切图片 + } + crypto.Digest fileMd5 = crypto.md5.convert(await temFile!.readAsBytes()); RestClient _client = await getClient(); BaseStructureResult resUploadConfig = await _client.getUploadFile(UploadFileInterfaceConfigParams( fileName: '1.png', @@ -459,7 +496,6 @@ class _ExamPaperDrawingState extends ConsumerState with EventB eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) { if (item.previousStep) { if (ref.read(drawMarkingProvider).data.isEmpty) { - ToastUtils.showInfo('批注已清空'); return; } var index = pointsPureData.toList().lastIndexOf(null); @@ -508,7 +544,7 @@ class _ExamPaperDrawingState extends ConsumerState with EventB isComplex: true, willChange: true, foregroundPainter: DrawingPainter(ctrl: _vnHandWritings), - child: RepaintBoundary(child: widget.child), + child: widget.child, ), ); } diff --git a/marking_app/lib/pages/marking/do_papers.dart b/marking_app/lib/pages/marking/do_papers.dart index 953b02e..27cec61 100644 --- a/marking_app/lib/pages/marking/do_papers.dart +++ b/marking_app/lib/pages/marking/do_papers.dart @@ -28,6 +28,7 @@ import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/common/upload_img_secret_key.dart'; import 'package:marking_app/common/model/enum/KeyboardType.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; +import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart'; import 'package:marking_app/common/model/marking/current_review_task.dart'; import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart'; import 'package:marking_app/common/model/marking/keyboard_assist_event.dart'; @@ -52,6 +53,8 @@ import 'package:marking_app/components/marking/review_records_view.dart'; import 'package:marking_app/components/marking/selectable_keyboard_bottom.dart'; import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/pages/marking/hooks/use_zoomImage_history_utils.dart'; +import 'package:marking_app/pages/marking/provider/do_paper_bottom_review_marks_provider.dart'; +import 'package:marking_app/pages/marking/provider/draw_marking_provider.dart'; import 'package:marking_app/pages/marking/provider/rating_progress_provider.dart'; import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart'; import 'package:marking_app/provider/do_marking_provider.dart'; @@ -158,6 +161,10 @@ class _MarkingPapersState extends ConsumerState fToast.init(context); Future.delayed(const Duration(seconds: 0)).then((onValue) { ref.read(annotationGraffitiSwitchProvider.notifier).init(); + // 重置批阅痕迹 + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], [])); + // 重置批阅动作按钮 + ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG); }); // 批注监听 @@ -460,15 +467,10 @@ class _MarkingPapersState extends ConsumerState RestClient client = await getClient(); String? commentImageUrlStr; - List? commentImageUrl = currentQuestion?.commentImageUrlTodo; - if (commentImageUrl?.isEmpty ?? true) commentImageUrl = currentQuestion?.commentImageUrl; + List? commentImageUrl = + (currentQuestion?.commentImageUrl.isNotEmpty ?? false) || res?.url != null ? currentQuestion?.commentImageUrlMap.values.toList() : null; if (commentImageUrl?.isNotEmpty ?? false) commentImageUrlStr = jsonEncode(commentImageUrl); - // bool excessContinue = - // _currentTab?.agreementExcess == null ? true : _currentTab!.agreementExcess!; // 如果没有询问默认为true 如果询问了 就已询问为主 - bool isExit = false; - MarkingTextQuestionTab? nextTag; - BaseStructureResult result = await client.submitTestQuestionsOfExam(SubmitExamParams( widget.markingUserId, detailId, @@ -1124,6 +1126,10 @@ class _MarkingPapersState extends ConsumerState setTimeOut(300, () => ToastUtils.showError('请求错诶,请重试')); throw Error(); } + // 重置批阅动作 + ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG); + // 重置批阅痕迹 + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], [])); currentQuestion = result.data; if (temTab != null) { result.data!.scoreInterval = temTab.scoreInterval ?? 1; @@ -1919,6 +1925,7 @@ class _MarkingPapersState extends ConsumerState // margin: EdgeInsets.only(top: 6.h), padding: EdgeInsets.symmetric(horizontal: 1.w), child: PictureOverview( + data: data, questionNum: data.questionNum, markingUserId: widget.markingUserId, key: pictureOverviewKey, @@ -1927,7 +1934,7 @@ class _MarkingPapersState extends ConsumerState annotationsFlag: annotationSwitch, commentImageMap: data.commentImageUrlMap, testQuestionNumber: widget.markingUserId.toString() + '-' + data.questionNum, - imageItems: data.getImageData(), + imageItems: data.studentAnswerList, ), ), From e727cb3d207ddec32526e5b03fd5a6454c0051fd Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 13 May 2024 14:50:07 +0800 Subject: [PATCH 07/15] no message --- .../android/app/src/main/AndroidManifest.xml | 17 +++- .../app/src/main/res/xml/file_paths.xml | 5 + .../app/src/profile/AndroidManifest.xml | 8 +- .../lib/components/PictureOverview.dart | 11 ++- marking_app/lib/pages/login/index.dart | 96 ++++++------------- marking_app/lib/pages/mainPage.dart | 3 +- .../lib/utils/app_upgrade/DownloadApk.dart | 29 +++--- .../lib/utils/app_upgrade/UpdateDialog.dart | 24 ++++- .../utils/app_upgrade/UpgradePermission.dart | 81 +++++++++++----- marking_app/pubspec.yaml | 2 + 10 files changed, 155 insertions(+), 121 deletions(-) create mode 100644 marking_app/android/app/src/main/res/xml/file_paths.xml diff --git a/marking_app/android/app/src/main/AndroidManifest.xml b/marking_app/android/app/src/main/AndroidManifest.xml index 5dc79c3..91aad8c 100644 --- a/marking_app/android/app/src/main/AndroidManifest.xml +++ b/marking_app/android/app/src/main/AndroidManifest.xml @@ -35,7 +35,14 @@ android:name="flutterEmbedding" android:value="2" /> - + + + + @@ -47,8 +54,10 @@ - - + + + + @@ -58,4 +67,6 @@ + + diff --git a/marking_app/android/app/src/main/res/xml/file_paths.xml b/marking_app/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..c4e8da4 --- /dev/null +++ b/marking_app/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/marking_app/android/app/src/profile/AndroidManifest.xml b/marking_app/android/app/src/profile/AndroidManifest.xml index 6281e88..186b8b4 100644 --- a/marking_app/android/app/src/profile/AndroidManifest.xml +++ b/marking_app/android/app/src/profile/AndroidManifest.xml @@ -13,9 +13,13 @@ - + - + + + + + diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 8c89dbb..c93a840 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -124,7 +124,8 @@ class PictureOverviewState extends ConsumerState with CommonMix } if (value.scale < 1) { initScale = value.scale; - Future.delayed(Duration(seconds: 5), () => ref.read(zoomHistoryProvider.notifier).setState(initScale!)); + // 5 + Future.delayed(Duration(seconds: 1), () => ref.read(zoomHistoryProvider.notifier).setState(initScale!)); } } }); @@ -270,15 +271,15 @@ class PictureOverviewState extends ConsumerState with CommonMix void onPanUpPosition(Offset val) async { // 手指在移动 非物体移动的位置 - print('**************** 正在移动位置 YYY:${val.dy}'); - print('**************** 正在移动位置 XXX:${val.dx}'); + // print('**************** 正在移动位置 YYY:${val.dy}'); + // print('**************** 正在移动位置 XXX:${val.dx}'); zoomOffset = val; } // 缩放组件 ==> 缩放监听 void onScaleUpdate(double scale, double zoom) async { - print('zoom:$zoom'); - print('scale:${scale}'); + // print('zoom:$zoom'); + // print('scale:${scale}'); // MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); double positionX = historyZoomInfo?.positionX ?? 0; diff --git a/marking_app/lib/pages/login/index.dart b/marking_app/lib/pages/login/index.dart index 2317dec..3c72178 100644 --- a/marking_app/lib/pages/login/index.dart +++ b/marking_app/lib/pages/login/index.dart @@ -44,10 +44,8 @@ class _TheLoginState extends ConsumerState with CommonMixin { //添加证书 setHttpsPEM() async { - (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = - (client) { - client.badCertificateCallback = - (X509Certificate cert, String host, int port) { + (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { + client.badCertificateCallback = (X509Certificate cert, String host, int port) { return true; }; }; @@ -75,7 +73,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { @override void initState() { - Future.delayed(Duration(seconds: 2), () => sysProtocol(context)); + Future.delayed(Duration(seconds: 1), () => sysProtocol(context)); Future(() { // 延迟更新 Provider ref.read(userTokenProvider.notifier).clean(); // 进入登录页先清空信息 @@ -89,14 +87,12 @@ class _TheLoginState extends ConsumerState with CommonMixin { receiveTimeout: 8000, ), ); - dio.interceptors - .add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志 + dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志 setHttpsPEM(); client = RestClient(dio, baseUrl: RequestConfig().loginBaseUrl); - _userNameController = TextEditingController() - ..addListener(userNameListener); + _userNameController = TextEditingController()..addListener(userNameListener); _passwordController = TextEditingController(); _pwdFocus = FocusNode(); _theFocus = FocusNode(); @@ -114,11 +110,10 @@ class _TheLoginState extends ConsumerState with CommonMixin { void getShowRegister() async { RestClient client = await getClientLogin(); BaseStructureResult resultData = await client.showRegister(); - if(resultData.success){ + if (resultData.success) { setState(() { showRegister = resultData.data; }); - } } @@ -126,8 +121,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { String userName = _userNameController.text; int useNameLength = userName.length; bool hasNameValNew = useNameLength > 0; - if (hasNameValNew != hasNameVal) - toUpState(setState, () => hasNameVal = hasNameValNew, mounted); + if (hasNameValNew != hasNameVal) toUpState(setState, () => hasNameVal = hasNameValNew, mounted); const isProd = bool.fromEnvironment('dart.vm.product'); if (!isProd && useNameLength == 11) { _passwordController.text = userName.substring(useNameLength - 6); @@ -182,15 +176,12 @@ class _TheLoginState extends ConsumerState with CommonMixin { child: SizedBox( height: 86.w, width: 86.w, - child: Image.asset('assets/images/logo.png', - fit: BoxFit.cover), + child: Image.asset('assets/images/logo.png', fit: BoxFit.cover), ), ), Container( - margin: EdgeInsets.symmetric( - horizontal: 32.w, vertical: 24.h), - padding: EdgeInsets.only( - top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), + margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h), + padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), decoration: BoxDecoration( color: Colors.white, border: Border.all(width: 1.w, color: Colors.white), @@ -219,18 +210,13 @@ class _TheLoginState extends ConsumerState with CommonMixin { ), decoration: InputDecoration( hintText: "请输入账号", - hintStyle: TextStyle( - fontSize: 16.sp, - color: const Color.fromRGBO(153, 153, 153, 1)), + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), labelText: "账号", - labelStyle: TextStyle( - fontSize: 16.sp, - color: const Color.fromRGBO(148, 163, 182, 1)), + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), suffixIcon: !hasNameVal ? null : Transform.translate( - offset: - Offset(10, 10), // 根据原始组件的padding值来设置偏移量 + offset: Offset(10, 10), // 根据原始组件的padding值来设置偏移量 child: IconButton( alignment: Alignment.center, padding: EdgeInsets.zero, @@ -266,19 +252,13 @@ class _TheLoginState extends ConsumerState with CommonMixin { onTap: _showPassword, child: Icon( Icons.remove_red_eye, - color: !_isShowPwd - ? Theme.of(context).primaryColor - : Colors.grey, + color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey, ), ), - hintStyle: TextStyle( - fontSize: 16.sp, - color: const Color.fromRGBO(153, 153, 153, 1)), + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), labelText: "密码", isDense: true, - labelStyle: TextStyle( - fontSize: 16.sp, - color: const Color.fromRGBO(148, 163, 182, 1)), + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), ), ), SizedBox( @@ -294,10 +274,8 @@ class _TheLoginState extends ConsumerState with CommonMixin { checkColor: Colors.white, value: keepPwd, onChanged: (value) { - FocusScope.of(context) - .requestFocus(_pwdFocus); - FocusScope.of(context) - .requestFocus(_theFocus); + FocusScope.of(context).requestFocus(_pwdFocus); + FocusScope.of(context).requestFocus(_theFocus); setState(() { keepPwd = value ?? false; }); @@ -322,15 +300,11 @@ class _TheLoginState extends ConsumerState with CommonMixin { if (showRegister == true) InkWell( onTap: () { - RouterManager.router.navigateTo( - context, RouterManager.registerPath); + RouterManager.router.navigateTo(context, RouterManager.registerPath); }, child: Text( '注册', - style: TextStyle( - fontSize: 14.sp, - color: const Color.fromRGBO( - 148, 163, 182, 1)), + style: TextStyle(fontSize: 14.sp, color: const Color.fromRGBO(148, 163, 182, 1)), )), ], ), @@ -339,9 +313,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { child: Container( margin: EdgeInsets.symmetric(vertical: 10.h), decoration: BoxDecoration( - color: canLogin - ? const Color.fromRGBO(9, 105, 246, 1) - : Colors.grey, + color: canLogin ? const Color.fromRGBO(9, 105, 246, 1) : Colors.grey, boxShadow: [ BoxShadow( color: const Color.fromRGBO(46, 91, 255, 0.5), @@ -359,8 +331,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { height: 50.h, child: Text( '登 录', - style: TextStyle( - fontSize: 16.sp, color: Colors.white), + style: TextStyle(fontSize: 16.sp, color: Colors.white), ), ), ), @@ -374,10 +345,8 @@ class _TheLoginState extends ConsumerState with CommonMixin { checkColor: Colors.white, value: readAgreement, onChanged: (value) { - FocusScope.of(context) - .requestFocus(_pwdFocus); - FocusScope.of(context) - .requestFocus(_theFocus); + FocusScope.of(context).requestFocus(_pwdFocus); + FocusScope.of(context).requestFocus(_theFocus); setState(() { readAgreement = value ?? false; }); @@ -458,22 +427,16 @@ class _TheLoginState extends ConsumerState with CommonMixin { print('userPwdMd5=$userPwdMd5'); EasyLoading.show(status: 'loading...'); try { - BaseStructureResult resultData = - await client.toLogin(UserLoginParams(userName, userPwdMd5)); - UserLogin? userData = resultData.code == 200 && resultData.data != null - ? UserLogin.fromJson(resultData.data) - : null; - if (resultData.code != 200 || - userData?.accessToken == null || - userData?.accessToken == '') { + BaseStructureResult resultData = await client.toLogin(UserLoginParams(userName, userPwdMd5)); + UserLogin? userData = resultData.code == 200 && resultData.data != null ? UserLogin.fromJson(resultData.data) : null; + if (resultData.code != 200 || userData?.accessToken == null || userData?.accessToken == '') { return toMsg(resultData.message ?? '登录失败,请重试'); } FastData fastData = FastData.getInstance(); fastData.setToken(userData!.accessToken); - BaseStructureResult userRes = - await client.getUserInfo('Bearer ${userData.accessToken}'); + BaseStructureResult userRes = await client.getUserInfo('Bearer ${userData.accessToken}'); if (userRes.code != 200 || userRes.data == null) { throw Exception('登录失败,请重试'); @@ -489,8 +452,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { ref.read(userTokenProvider.notifier).initToken(); // 跳转登录页 - RouterManager.router.navigateTo(context, RouterManager.root, - clearStack: true, transition: getTransition()); + RouterManager.router.navigateTo(context, RouterManager.root, clearStack: true, transition: getTransition()); }); } catch (e) { toPrint(val: e.toString()); diff --git a/marking_app/lib/pages/mainPage.dart b/marking_app/lib/pages/mainPage.dart index 8c76648..ffb6307 100644 --- a/marking_app/lib/pages/mainPage.dart +++ b/marking_app/lib/pages/mainPage.dart @@ -28,6 +28,7 @@ import 'package:marking_app/provider/user_provider.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:package_info/package_info.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'homework_correction/job_home.dart'; @@ -104,7 +105,7 @@ class TheMainPageState extends ConsumerState with CommonMixin { } void getAppUpgrade(UserInfo user) async { - if (!bool.fromEnvironment('dart.vm.product')) return; + // if (!bool.fromEnvironment('dart.vm.product')) return; try { showUpgrade = true; if (['18888888888'].contains(user.loginName)) return; diff --git a/marking_app/lib/utils/app_upgrade/DownloadApk.dart b/marking_app/lib/utils/app_upgrade/DownloadApk.dart index 2aeda91..331684f 100644 --- a/marking_app/lib/utils/app_upgrade/DownloadApk.dart +++ b/marking_app/lib/utils/app_upgrade/DownloadApk.dart @@ -6,6 +6,7 @@ * @LastEditors: wangyang 1147192855@qq.com * @LastEditTime: 2022-08-02 15:12:21 */ +import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; @@ -13,11 +14,10 @@ import 'package:flutter/cupertino.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:install_plugin/install_plugin.dart'; import 'package:marking_app/provider/upgrade_provider.dart'; -// import 'package:install_plugin_v2/install_plugin_v2.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; -import 'package:marking_app/utils/index.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:app_installer/app_installer.dart'; class DownloadApk { /// 下载安卓更新包 @@ -58,9 +58,7 @@ class DownloadApk { debugPrint('make sure the apk file is set'); return false; } - Map statuses = await [Permission.storage].request(); - if (statuses[Permission.storage]!.isGranted) { // String? result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName).catchError((error) { // debugPrint('install apk error: $error'); @@ -68,16 +66,17 @@ class DownloadApk { // debugPrint('install apk $result'); // ToastUtils.getFluttertoast(context: context, msg: 'install apk $result'); try { - final result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName); - print('这是是执行安装的程序:' + result.runtimeType.toString()); - if (result['isSuccess'] ?? false) { - ToastUtils.showSuccess('install apk $result'); - RestartWidget.restartApp(context); // 安装成功 重启APP - return true; - } - } catch (e) {} - } else { - debugPrint('Permission request fail!'); + // InstallPlugin.install(filePathOrUrlString)com.example.marking_app + await AppInstaller.installApk(_apkFilePath); + // var result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName); + // print('这是是执行安装的程序:' + jsonEncode(result)); + // if (!(result?['isSuccess'] ?? false)) {} + // Restadget.restartApp(context); // 安装成功 重启APP + print('安装执行完成了..............0.0'); + } catch (e) { + print('安装进入报错....'); + print(e); + } } return false; @@ -87,7 +86,7 @@ class DownloadApk { static void showDownloadProgress(context, num received, num total, WidgetRef ref) { if (total != -1) { double progress = double.parse((received / total).toStringAsFixed(2)); - debugPrint('下载进度$progress'); + // debugPrint('下载进度$progress'); ref.read(upgradeProvider.notifier).setVal(progress); } } diff --git a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart index f16a0f9..ef60cac 100644 --- a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart +++ b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart @@ -14,7 +14,6 @@ * @LastEditors: Please set LastEditors * @LastEditTime: 2021-01-12 15:08:43 */ -import 'dart:async'; import 'package:clipboard/clipboard.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -27,6 +26,7 @@ import 'package:marking_app/utils/my_text.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher_string.dart'; class UpdateDialog extends Dialog { @@ -145,6 +145,19 @@ class DownloadButton extends ConsumerWidget { final String deviceInfo; const DownloadButton(this.updateAppEvent, {required this.deviceInfo, Key? key}) : super(key: key); + // 打开浏览器或者对应的对应市场进行下载 + Future toLaunch(UpdateAppEvent data) async { + var uri = Uri.parse('market://details?id=com.example.marking_app'); + if (await canLaunchUrl(uri)) { + // 跳进对应的应用市场进行更新操作 + return await launchUrl(uri); + } + // 无法进入应用市场就打开浏览器进行下载 + uri = Uri.parse(data.link); + if (await canLaunchUrl(uri)) return await launchUrl(uri); + return false; + } + @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(upgradeProvider); @@ -163,7 +176,8 @@ class DownloadButton extends ConsumerWidget { child: MaterialButton( onPressed: () => easyThrottle('DownloadButton_App_Upgrade', () async { if (deviceInfo == "android" && updateAppEvent.equipment == Equipment.android) { - bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(); + // 权限检查 判断是否有读写内存的权限 + bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context); if (flag) { flag = await DownloadApk.installApk(context, updateAppEvent, ref); @@ -176,8 +190,10 @@ class DownloadButton extends ConsumerWidget { } return; } - await FlutterClipboard.copy(updateAppEvent.link); - setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装')); + // 进入应用市场进行下载 + await toLaunch(updateAppEvent); + // await FlutterClipboard.copy(updateAppEvent.link); + // setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装')); } else if (deviceInfo == "ios" && updateAppEvent.equipment == Equipment.ios) { try { await launchUrlString(updateAppEvent.link); diff --git a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart index 1337eca..6ca4b8c 100644 --- a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart +++ b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart @@ -6,6 +6,8 @@ * @LastEditors: wangyang 1147192855@qq.com * @LastEditTime: 2022-08-01 14:08:57 */ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/utils/index.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -14,34 +16,65 @@ class UpgradePermission { const UpgradePermission(this._flatform); /// 检查是否有权限,用于安卓 - Future checkPermission() async { - // if (_flatform == 'android') { + Future checkPermission(BuildContext context) async { + if (_flatform != 'android') return true; // 非安卓 + var status = await Permission.storage.request(); + if (status.isGranted) return true; - // return await Permission.storage.request().isGranted; - // } else { - // return true; - // } + if (status.isDenied) { + // 普通拒绝 可以再进行提示 + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("权限提示"), + content: const Text("无法获取存储权限,请同意获取设备存储权限"), + actions: [ + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("同意", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ); + }, + ); - if (_flatform == 'android') { - final status = await Permission.storage.status; - if (status != PermissionStatus.granted) { - final result = await Permission.storage.request(); - if (result == PermissionStatus.granted) { - return true; - } - if (status == PermissionStatus.denied) { - ToastUtils.showError('拒绝了保存安装权限'); - } - - if (status == PermissionStatus.permanentlyDenied) { - ToastUtils.showError('用户永久拒绝保存安装权限,请前往设置权限'); - } - } else { - return true; + if (isPad()) { + // 平板无法发起权限询问 直接进入APP权限设置页面 + await openAppSettings(); + return false; } - } else { - return true; + + return checkPermission(context); } + + // 拒绝并不再提示 + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("权限提示"), + content: const Text("储存权限被永久拒绝,并且不再提示。请前往设置页面同意储存权限"), + actions: [ + MaterialButton( + color: Colors.green.shade900, + child: const Text("退出APP", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(false), + ), + MaterialButton( + color: Colors.green.shade900, + child: const Text("确定", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ); + }, + ); + + await openAppSettings(); return false; } } diff --git a/marking_app/pubspec.yaml b/marking_app/pubspec.yaml index 0c52cc6..324ff6a 100644 --- a/marking_app/pubspec.yaml +++ b/marking_app/pubspec.yaml @@ -114,6 +114,8 @@ dependencies: flutter_staggered_grid_view: ^0.6.2 # 饼图 flutter_echart: ^2.0.0 + app_installer: ^1.1.0 + dev_dependencies: From 309c708847efa960dc820ac39a3e80cf4e653cf7 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 13 May 2024 18:42:41 +0800 Subject: [PATCH 08/15] no message --- .../lib/utils/app_upgrade/DownloadApk.dart | 60 ++++++--- .../lib/utils/app_upgrade/UpdateDialog.dart | 5 +- .../utils/app_upgrade/UpgradePermission.dart | 118 +++++++++++++++--- 3 files changed, 146 insertions(+), 37 deletions(-) diff --git a/marking_app/lib/utils/app_upgrade/DownloadApk.dart b/marking_app/lib/utils/app_upgrade/DownloadApk.dart index 331684f..081156b 100644 --- a/marking_app/lib/utils/app_upgrade/DownloadApk.dart +++ b/marking_app/lib/utils/app_upgrade/DownloadApk.dart @@ -11,13 +11,18 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:install_plugin/install_plugin.dart'; import 'package:marking_app/provider/upgrade_provider.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; +import 'package:marking_app/utils/index.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:path_provider/path_provider.dart'; import 'package:app_installer/app_installer.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'UpgradePermission.dart'; class DownloadApk { /// 下载安卓更新包 @@ -58,25 +63,42 @@ class DownloadApk { debugPrint('make sure the apk file is set'); return false; } - Map statuses = await [Permission.storage].request(); - if (statuses[Permission.storage]!.isGranted) { - // String? result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName).catchError((error) { - // debugPrint('install apk error: $error'); - // }); - // debugPrint('install apk $result'); - // ToastUtils.getFluttertoast(context: context, msg: 'install apk $result'); - try { - // InstallPlugin.install(filePathOrUrlString)com.example.marking_app - await AppInstaller.installApk(_apkFilePath); - // var result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName); - // print('这是是执行安装的程序:' + jsonEncode(result)); - // if (!(result?['isSuccess'] ?? false)) {} - // Restadget.restartApp(context); // 安装成功 重启APP - print('安装执行完成了..............0.0'); - } catch (e) { - print('安装进入报错....'); - print(e); - } + try { + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("未知应用安装权限提示"), + content: const Text("更新时若出现需要同意安装未知应用权限时,请同意"), + actions: [ + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("我已知晓", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ); + }, + ); + await AppInstaller.installApk(_apkFilePath); // 安装APK + // 如果2秒还没有进入安装引导页面 一律视为更新失败,弹出其他方式更新 + await setTimeOut(5000, () async { + try { + // 其他方式下载 + // await SystemNavigator.pop(); // 退出APP + var options = ['应用市场更新APP', '浏览器下载并安装APP']; + var uri = Uri.parse('market://details?id=com.example.marking_app'); // 应用市场URI + if (!await canLaunchUrl(uri)) options.removeAt(0); // 如果不能打开应用市场 就屏蔽掉 这个安装方式 + String? option = await UpgradePermission.showCustomModalBottomSheet(context, options); + if (option == '应用市场更新APP') await launchUrl(uri); + if (option == '浏览器下载并安装APP') await launchUrl(Uri.parse(event.link)); + } catch (e) {} + }); + + print('安装执行完成了..............0.0'); + } catch (e) { + print('安装进入报错....'); + print(e); } return false; diff --git a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart index ef60cac..98e6e66 100644 --- a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart +++ b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart @@ -177,10 +177,9 @@ class DownloadButton extends ConsumerWidget { onPressed: () => easyThrottle('DownloadButton_App_Upgrade', () async { if (deviceInfo == "android" && updateAppEvent.equipment == Equipment.android) { // 权限检查 判断是否有读写内存的权限 - bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context); + bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context, updateAppEvent); if (flag) { flag = await DownloadApk.installApk(context, updateAppEvent, ref); - if (!flag) { print('执行到了重置更新按钮的地方....'); ref.read(upgradeProvider.notifier).clean(); // 更新失败重置 更新按钮 @@ -190,8 +189,6 @@ class DownloadButton extends ConsumerWidget { } return; } - // 进入应用市场进行下载 - await toLaunch(updateAppEvent); // await FlutterClipboard.copy(updateAppEvent.link); // setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装')); } else if (deviceInfo == "ios" && updateAppEvent.equipment == Equipment.ios) { diff --git a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart index 6ca4b8c..07badba 100644 --- a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart +++ b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart @@ -6,23 +6,50 @@ * @LastEditors: wangyang 1147192855@qq.com * @LastEditTime: 2022-08-01 14:08:57 */ +import 'package:app_installer/app_installer.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/utils/index.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'model/UpdateAppEvent.dart'; class UpgradePermission { final String _flatform; const UpgradePermission(this._flatform); /// 检查是否有权限,用于安卓 - Future checkPermission(BuildContext context) async { + /// noExecutions 执行次数 + Future checkPermission(BuildContext context, UpdateAppEvent updateAppEvent, [int? noExecutions]) async { + noExecutions ??= 1; if (_flatform != 'android') return true; // 非安卓 var status = await Permission.storage.request(); if (status.isGranted) return true; if (status.isDenied) { // 普通拒绝 可以再进行提示 + + if (noExecutions == 3) { + // 拒绝并不再提示 或者某些机型不会提示 + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("提示"), + content: const Text("若“拒绝并不再提示”或“没有弹出权限询问对话框”,再次点击同意按钮出现其他更新方式。"), + actions: [ + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("确定", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(), + ) + ], + ); + }, + ); + } + await showDialog( context: context, barrierDismissible: false, @@ -41,17 +68,18 @@ class UpgradePermission { }, ); - if (isPad()) { - // 平板无法发起权限询问 直接进入APP权限设置页面 - await openAppSettings(); - return false; - } + // if (isPad()) { + // // 平板无法发起权限询问 直接进入APP权限设置页面 + // await openAppSettings(); + // return false; + // } - return checkPermission(context); + if (noExecutions <= 2) return checkPermission(context, updateAppEvent, ++noExecutions); + // 执行次数大于3次,就不再询问直接打开设置权限页面(防止某些机型不会弹起权限询问交互弹框) } // 拒绝并不再提示 - await showDialog( + bool? res = await showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { @@ -61,20 +89,82 @@ class UpgradePermission { actions: [ MaterialButton( color: Colors.green.shade900, - child: const Text("退出APP", style: TextStyle(color: Colors.white)), + child: const Text("其它方式更新", style: TextStyle(color: Colors.white)), onPressed: () => Navigator.of(context).pop(false), ), MaterialButton( - color: Colors.green.shade900, - child: const Text("确定", style: TextStyle(color: Colors.white)), + color: Theme.of(context).primaryColor, + child: const Text("前往设置", style: TextStyle(color: Colors.white)), onPressed: () => Navigator.of(context).pop(true), ), ], ); }, ); - - await openAppSettings(); + if (res == null || !res) { + // 其他方式下载 + // await SystemNavigator.pop(); // 退出APP + var options = ['应用市场更新APP', '浏览器下载并安装APP']; + var uri = Uri.parse('market://details?id=com.example.marking_app'); // 应用市场URI + // if (!await canLaunchUrl(uri)) options.removeAt(0); // 如果不能打开应用市场 就屏蔽掉 这个安装方式 + String? option = await showCustomModalBottomSheet(context, options); + if (option == '应用市场更新APP') { + if (await canLaunchUrl(uri)) + await launchUrl(uri); + else + await AppInstaller.goStore('com.example.marking_app', 'iOSAppId'); + } + if (option == '浏览器下载并安装APP') await launchUrl(Uri.parse(updateAppEvent.link)); + } else + await openAppSettings(); return false; } + + // 其他方式下载选择 + static Future showCustomModalBottomSheet(context, List options) async { + return showModalBottomSheet( + backgroundColor: Colors.transparent, + isScrollControlled: true, + context: context, + builder: (BuildContext context) { + return Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(20.0), + topRight: const Radius.circular(20.0), + ), + ), + height: MediaQuery.of(context).size.height / 4.0, + child: Column(children: [ + SizedBox( + height: 50, + child: Stack( + textDirection: TextDirection.rtl, + children: [ + Center(child: Text('选择其它方式更新APP', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0))), + IconButton(icon: Icon(Icons.close), onPressed: () => Navigator.of(context).pop()), + ], + ), + ), + Divider(height: 1.0), + Expanded( + child: ListView.builder( + itemCount: options.length, + itemBuilder: (BuildContext context, int index) { + var name = options[index]; + return ListTile( + title: Text(name), + trailing: Icon(name.contains('浏览器') ? Icons.browser_updated_outlined : Icons.local_grocery_store_outlined), + onTap: () => Navigator.of(context).pop(name), + ); + }, + ), + ), + ]), + ); + }, + ); + } } From b52c335c65424687cf62f29c32f1033e460e6824 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Tue, 14 May 2024 13:53:17 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8D=87=E7=BA=A7APP?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- marking_app/lib/pages/login/index.dart | 62 +++++++++++++++---- marking_app/lib/pages/mainPage.dart | 8 ++- .../lib/utils/app_upgrade/DownloadApk.dart | 13 ++-- .../lib/utils/app_upgrade/UpdateDialog.dart | 3 +- .../utils/app_upgrade/UpgradePermission.dart | 32 +--------- 5 files changed, 64 insertions(+), 54 deletions(-) diff --git a/marking_app/lib/pages/login/index.dart b/marking_app/lib/pages/login/index.dart index 3c72178..8095459 100644 --- a/marking_app/lib/pages/login/index.dart +++ b/marking_app/lib/pages/login/index.dart @@ -12,6 +12,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:dio/adapter.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -309,7 +310,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { ], ), InkWell( - onTap: toLogin, + onTap: () => easyThrottle('TO_GO_LOGOIN', toLogin), child: Container( margin: EdgeInsets.symmetric(vertical: 10.h), decoration: BoxDecoration( @@ -415,18 +416,54 @@ class _TheLoginState extends ConsumerState with CommonMixin { setState(() => canLogin = true); } - FocusScope.of(context).requestFocus(_theFocus); - - String userName = _userNameController.text.trim(); - String userPwd = _passwordController.text.trim(); - if (userName == '') return toMsg('请填写用户账号'); - if (userPwd == '') return toMsg('请填写密码再试'); - if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); - - String userPwdMd5 = CommonUtils.generateMD5(userPwd); - print('userPwdMd5=$userPwdMd5'); - EasyLoading.show(status: 'loading...'); try { + FocusScope.of(context).requestFocus(_theFocus); + if (!readAgreement) { + var resFlag = await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: quickText('用户协议及隐私协议', size: 14.sp, color: Color.fromARGB(255, 53, 52, 52)), + content: SingleChildScrollView( + padding: EdgeInsets.only(top: 4.h), + child: RichText( + text: TextSpan( + text: '为了更好地保障您的合法权益,请您阅读并同意以下协议', + style: TextStyle(color: Color.fromARGB(255, 137, 138, 139), fontSize: 11.sp), + children: [ + TextSpan(text: '《用户协议》《隐式协议》', style: TextStyle(color: Colors.deepOrangeAccent, fontSize: 13.sp)), + ], + ), + ), + ), + actions: [ + CupertinoDialogAction( + child: Text("取消", style: TextStyle(color: Color.fromARGB(255, 58, 58, 58))), + onPressed: () => Navigator.of(context).pop(false), + ), + CupertinoDialogAction( + child: Text("确定"), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ); + }, + ); + if (!resFlag!) return; + setState(() => readAgreement = true); + } + + String userName = _userNameController.text.trim(); + String userPwd = _passwordController.text.trim(); + if (userName == '') return toMsg('请填写用户账号'); + if (userPwd == '') return toMsg('请填写密码再试'); + if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); + + String userPwdMd5 = CommonUtils.generateMD5(userPwd); + print('userPwdMd5=$userPwdMd5'); + EasyLoading.show(status: 'loading...'); + BaseStructureResult resultData = await client.toLogin(UserLoginParams(userName, userPwdMd5)); UserLogin? userData = resultData.code == 200 && resultData.data != null ? UserLogin.fromJson(resultData.data) : null; if (resultData.code != 200 || userData?.accessToken == null || userData?.accessToken == '') { @@ -484,6 +521,7 @@ class _TheLoginState extends ConsumerState with CommonMixin { return toMsg(msg ?? '登录失败,请重试'); } finally { EasyLoading.dismiss(); + setState(() => canLogin = true); } } } diff --git a/marking_app/lib/pages/mainPage.dart b/marking_app/lib/pages/mainPage.dart index ffb6307..7bea9b9 100644 --- a/marking_app/lib/pages/mainPage.dart +++ b/marking_app/lib/pages/mainPage.dart @@ -19,6 +19,7 @@ import 'package:marking_app/common/model/user/user_info.dart'; import 'package:marking_app/pages/reports/index.dart'; import 'package:marking_app/provider/do_marking_provider.dart'; import 'package:marking_app/provider/upload_file_provider.dart'; +import 'package:marking_app/routes/RouterManager.dart'; import 'package:marking_app/utils/app_upgrade/UpdateDialog.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; import 'package:marking_app/common/model/sys/system_version.dart'; @@ -73,10 +74,11 @@ class TheMainPageState extends ConsumerState with CommonMixin { // 由于本项目必须登录才能浏览,所以APP升级校验在登录后 _userListener = ref.read(userProvider.notifier).addListener((state) { if (state.id != '0' && state.id != '') { - if (!showUpgrade) { - getAppUpgrade(state); - } + if (!showUpgrade) getAppUpgrade(state); + _timer?.cancel(); _timer = Timer.periodic(Duration(seconds: 40), (e) { + String? routeName = ModalRoute.of(context)?.settings.name; + if (routeName == RouterManager.loginPath) return; // 在登录页面不更新APP if (!showUpgrade) getAppUpgrade(state); }); } diff --git a/marking_app/lib/utils/app_upgrade/DownloadApk.dart b/marking_app/lib/utils/app_upgrade/DownloadApk.dart index 081156b..1c09368 100644 --- a/marking_app/lib/utils/app_upgrade/DownloadApk.dart +++ b/marking_app/lib/utils/app_upgrade/DownloadApk.dart @@ -6,18 +6,14 @@ * @LastEditors: wangyang 1147192855@qq.com * @LastEditTime: 2022-08-02 15:12:21 */ -import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:install_plugin/install_plugin.dart'; import 'package:marking_app/provider/upgrade_provider.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; import 'package:marking_app/utils/index.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'package:path_provider/path_provider.dart'; import 'package:app_installer/app_installer.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -68,12 +64,15 @@ class DownloadApk { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text("未知应用安装权限提示"), - content: const Text("更新时若出现需要同意安装未知应用权限时,请同意"), + title: const Text("未知应用安装权限提示", + style: TextStyle( + fontWeight: FontWeight.bold, + )), + content: const Text("请注意:更新时若出现需要同意“安装未知应用权限”,请同意!!!"), actions: [ MaterialButton( color: Theme.of(context).primaryColor, - child: const Text("我已知晓", style: TextStyle(color: Colors.white)), + child: const Text("我已知晓", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), onPressed: () => Navigator.of(context).pop(), ), ], diff --git a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart index 98e6e66..6ba8e40 100644 --- a/marking_app/lib/utils/app_upgrade/UpdateDialog.dart +++ b/marking_app/lib/utils/app_upgrade/UpdateDialog.dart @@ -14,7 +14,6 @@ * @LastEditors: Please set LastEditors * @LastEditTime: 2021-01-12 15:08:43 */ -import 'package:clipboard/clipboard.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/provider/upgrade_provider.dart'; @@ -174,7 +173,7 @@ class DownloadButton extends ConsumerWidget { ]), ), child: MaterialButton( - onPressed: () => easyThrottle('DownloadButton_App_Upgrade', () async { + onPressed: () => easyThrottle('DownloadButton_App_Upgrade', duration: const Duration(milliseconds: 1000), () async { if (deviceInfo == "android" && updateAppEvent.equipment == Equipment.android) { // 权限检查 判断是否有读写内存的权限 bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context, updateAppEvent); diff --git a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart index 07badba..eaa6dda 100644 --- a/marking_app/lib/utils/app_upgrade/UpgradePermission.dart +++ b/marking_app/lib/utils/app_upgrade/UpgradePermission.dart @@ -8,7 +8,6 @@ */ import 'package:app_installer/app_installer.dart'; import 'package:flutter/material.dart'; -import 'package:marking_app/utils/index.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -29,27 +28,6 @@ class UpgradePermission { if (status.isDenied) { // 普通拒绝 可以再进行提示 - if (noExecutions == 3) { - // 拒绝并不再提示 或者某些机型不会提示 - await showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - title: const Text("提示"), - content: const Text("若“拒绝并不再提示”或“没有弹出权限询问对话框”,再次点击同意按钮出现其他更新方式。"), - actions: [ - MaterialButton( - color: Theme.of(context).primaryColor, - child: const Text("确定", style: TextStyle(color: Colors.white)), - onPressed: () => Navigator.of(context).pop(), - ) - ], - ); - }, - ); - } - await showDialog( context: context, barrierDismissible: false, @@ -68,14 +46,8 @@ class UpgradePermission { }, ); - // if (isPad()) { - // // 平板无法发起权限询问 直接进入APP权限设置页面 - // await openAppSettings(); - // return false; - // } - - if (noExecutions <= 2) return checkPermission(context, updateAppEvent, ++noExecutions); - // 执行次数大于3次,就不再询问直接打开设置权限页面(防止某些机型不会弹起权限询问交互弹框) + if (noExecutions < 2) return checkPermission(context, updateAppEvent, ++noExecutions); + // 执行次数大于2次,就不再询问直接打开设置权限页面(防止某些机型不会弹起权限询问交互弹框) } // 拒绝并不再提示 From 6dca9d8f0e8d86361dd0e92baffd20f7dde68c1a Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Tue, 14 May 2024 16:17:50 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E5=A4=84=E7=90=86=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E7=BC=A9=E6=94=BE=E5=8F=98=E5=B0=8F=E5=9D=90=E6=A0=87=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/components/PictureOverview.dart | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index c93a840..5dc23ec 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -292,7 +292,7 @@ class PictureOverviewState extends ConsumerState with CommonMix markingUserId: widget.markingUserId, ); zoomInfo = info; - if (double.parse(zoom.toStringAsFixed(2)) <= 1) zoom = 1; + // if (double.parse(zoom.toStringAsFixed(2)) <= 1) zoom = 1; if (imagInfoModel != null) { // 根据缩放比例重置被放大的图片的尺寸 imagInfoModel = TestQuestionsImageInfo( @@ -374,41 +374,51 @@ class PictureOverviewState extends ConsumerState with CommonMix globalPosition = details.localPosition; Offset localPosition = globalPosition!; - if (imagInfoModel != null && - (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { - // 笔迹画出图片区域 直接断笔 - var dataVal = ref.read(drawMarkingProvider).data; - if (dataVal.length - 1 > -1 && dataVal[dataVal.length - 1].data != null) { - var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); - var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); - ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); - } - illegalArea = true; - return; - } - illegalArea = false; + // if (imagInfoModel != null && + // (localPosition.dy < imagInfoModel!.imageHeightOffsetStart! || localPosition.dy > imagInfoModel!.imageHeightOffsetend!)) { + // // 笔迹画出图片区域 直接断笔 + // var dataVal = ref.read(drawMarkingProvider).data; + // if (dataVal.length - 1 > -1 && dataVal[dataVal.length - 1].data != null) { + // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + // var newVal1 = ref.read(drawMarkingProvider).offsets..add(null); + // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); + // } + // illegalArea = true; + // return; + // } + // illegalArea = false; + + var _theKey = _zoomKey.currentState; + print(_theKey); double remainingHeight = imagInfoModel!.imageHeightOffsetStart!; // 剩余高度 if (remainingHeight > 1) { localPosition = Offset(localPosition.dx, localPosition.dy - remainingHeight); - - // if (zoomOffset != null) { - // // var density = (imagInfoModel!.boxWidth / imagInfoModel!.scaleWidth!); - // localPosition = Offset(localPosition.dx/, localPosition.dy); - // } - } else { - if (zoomOffset != null) { - localPosition = Offset(localPosition.dx, localPosition.dy + zoomOffset!.dy.abs()); - } } - if (imagInfoModel?.zoom != null && imagInfoModel?.zoom != 1) { + // print(localPosition.dy); + print(localPosition.dx); + + double _theZoomVal = imagInfoModel?.zoom ?? 1; + var _dx = zoomOffset?.dx ?? 0; + _dx = _dx > 0 ? 0 : _dx.abs() / _theZoomVal; + var _dy = zoomOffset?.dy ?? 0; + _dy = _dy > 0 ? 0 : _dy.abs() / _theZoomVal; + + if (_theZoomVal > 1) { // 计算视图被放大比例 还原笔迹坐标 - localPosition = Offset(localPosition.dx / imagInfoModel!.zoom, localPosition.dy / imagInfoModel!.zoom); + localPosition = Offset(localPosition.dx / _theZoomVal, localPosition.dy / _theZoomVal); if (zoomOffset != null) { // 如果滚动条有触动就加上滚动条滚动的位置 - localPosition = Offset(localPosition.dx + zoomOffset!.dx.abs() / imagInfoModel!.zoom, localPosition.dy); + localPosition = Offset(localPosition.dx + _dx, localPosition.dy + _dy); } + } else if (_theZoomVal < 1) { + // 试图被缩小 + double imgSpaceWidthOfSingle = (imagInfoModel!.boxWidth - imagInfoModel!.scaleWidth!) / 2; + localPosition = Offset((localPosition.dx - imgSpaceWidthOfSingle) / _theZoomVal, localPosition.dy / _theZoomVal + _dy); + // localPosition = Offset(localPosition.dx * _theZoomVal - imgSpaceWidthOfSingle, localPosition.dy / _theZoomVal); + } else { + localPosition = Offset(localPosition.dx, localPosition.dy + _dy); } var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser, data: localPosition)); From f13bdbcf5f698fa588d6c1d50a7108463b3ff7c4 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Tue, 14 May 2024 18:17:15 +0800 Subject: [PATCH 11/15] no message --- .../lib/components/PictureOverview.dart | 6 +- .../do_paper_bottom_review_marks.dart | 28 +++++- marking_app/lib/pages/marking/do_papers.dart | 99 +++++++++---------- 3 files changed, 77 insertions(+), 56 deletions(-) diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 5dc23ec..8bb4258 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -71,6 +71,7 @@ class PictureOverview extends StatefulHookConsumerWidget { final String testQuestionNumber; final Map commentImageMap; final MarkingTextQuestion data; + final Function callAnnotationTips; const PictureOverview({ required this.imageItems, @@ -80,6 +81,7 @@ class PictureOverview extends StatefulHookConsumerWidget { required this.questionNum, required this.markingUserId, required this.data, + required this.callAnnotationTips, this.homework = false, this.imageScale = 1, this.imagePosition, @@ -139,6 +141,7 @@ class PictureOverviewState extends ConsumerState with CommonMix // 事件总线监听 清空数据 eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) async { + widget.callAnnotationTips(); // 调用回调 通知父级批注记录被更改 if (ref.read(drawMarkingProvider).data.isEmpty) { if (widget.data.commentImageUrl.isNotEmpty) { bool? res = await showDialog( @@ -146,7 +149,7 @@ class PictureOverviewState extends ConsumerState with CommonMix barrierDismissible: false, context: context, builder: (context1) { - return AlertDialog(content: quickText("是否撤销上次批注痕迹"), actions: [ + return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹"), actions: [ TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)), TextButton(child: quickText("确定", color: Theme.of(context).primaryColor), onPressed: () => Navigator.pop(context1, true)) ]); @@ -424,6 +427,7 @@ class PictureOverviewState extends ConsumerState with CommonMix var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser, data: localPosition)); var newVal1 = ref.read(drawMarkingProvider).offsets..add(localPosition); ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1)); + widget.callAnnotationTips(); }, // onPointerDown: (PointerDownEvent event) { // }, diff --git a/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart b/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart index 3185981..6e78354 100644 --- a/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart +++ b/marking_app/lib/pages/marking/components/do_paper_bottom_review_marks.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -5,6 +6,7 @@ import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart import 'package:marking_app/common/model/event_bus/bottom_annotation_switch_cleanall.dart'; import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/utils/anti_shake_throttling.dart'; +import 'package:marking_app/utils/my_text.dart'; import '../provider/do_paper_bottom_review_marks_provider.dart'; @@ -84,7 +86,31 @@ class _DoPaperBottomReviewMarksState extends ConsumerState easyThrottle( 'REVIEW_MARKS_BOTTOM_BTNS', duration: const Duration(milliseconds: 100), - () => eventFire(model: BottomAnnotationSwitchCleanallOfMarking(cleanAll: true)), + () async { + var resFlag = await showDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: quickText('撤销批阅痕迹', size: 14.sp, color: Color.fromARGB(255, 53, 52, 52)), + content: SingleChildScrollView( + padding: EdgeInsets.only(top: 4.h), + child: RichText(text: TextSpan(text: '请确认需要撤销所有批阅痕迹?', style: TextStyle(color: Color.fromARGB(255, 58, 58, 58)))), + ), + actions: [ + CupertinoDialogAction( + child: Text("取消", style: TextStyle(color: Color.fromARGB(255, 58, 58, 58))), + onPressed: () => Navigator.of(context).pop(false), + ), + CupertinoDialogAction( + child: Text("确定"), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ); + }, + ); + if (resFlag == true) eventFire(model: BottomAnnotationSwitchCleanallOfMarking(cleanAll: true)); + }, ), padding: EdgeInsets.zero, icon: Icon(Icons.reply_all_outlined, color: btnEnum == ReviewMarksBottomBtnsEnum.CLEAR_ALL ? actionColor : Colors.white, size: 34.r), diff --git a/marking_app/lib/pages/marking/do_papers.dart b/marking_app/lib/pages/marking/do_papers.dart index 27cec61..fd45696 100644 --- a/marking_app/lib/pages/marking/do_papers.dart +++ b/marking_app/lib/pages/marking/do_papers.dart @@ -14,6 +14,7 @@ import 'package:achievement_view/achievement_view.dart'; import 'package:collection/collection.dart'; import 'package:dotted_border/dotted_border.dart'; import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -29,6 +30,7 @@ import 'package:marking_app/common/model/common/upload_img_secret_key.dart'; import 'package:marking_app/common/model/enum/KeyboardType.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; import 'package:marking_app/common/model/enum/review_marks_bottom_btns_enum.dart'; +import 'package:marking_app/common/model/event_bus/bottom_annotation_switch_cleanall.dart'; import 'package:marking_app/common/model/marking/current_review_task.dart'; import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart'; import 'package:marking_app/common/model/marking/keyboard_assist_event.dart'; @@ -142,6 +144,7 @@ class _MarkingPapersState extends ConsumerState bool _completionPromptTab = false; // tab下试题完成并提示 bool _reviewCompletedPrompted = false; // 已经批阅完成提示 + bool annotationTips = false; // 批注提示(用于已批注但未提交) // bool _switchQueTypePrompt = false; // 切换题型 @@ -195,6 +198,7 @@ class _MarkingPapersState extends ConsumerState setTimeOut(300, () { eventFireSub(model: SwitchKeyboardToReloadImages(true)); }); + eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) async {}); }); params = MarkingTextQuestionParams( @@ -506,6 +510,7 @@ class _MarkingPapersState extends ConsumerState e.isFinish = true; } } + annotationTips = false; // ScaffoldMessenger.of(context).showSnackBar( // SnackBar( @@ -757,6 +762,39 @@ class _MarkingPapersState extends ConsumerState return ToastUtils.getFluttertoast(context: context, msg: '请先评分后提交再进入下一题'); } + print(annotationTips); + if (annotationTips && currentQuestion != null) { + // 改变批注未提交 需要提示 + var resFlag = await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: quickText('未提交批注提示', size: 14.sp, color: Color.fromARGB(255, 53, 52, 52)), + content: SingleChildScrollView( + padding: EdgeInsets.only(top: 4.h), + child: RichText(text: TextSpan(text: '当前批注未提交切换试题将清空本次笔迹,是否继续?', style: TextStyle(color: Color.fromARGB(255, 58, 58, 58)))), + ), + actions: [ + CupertinoDialogAction( + child: Text("提交", style: TextStyle(color: Color.fromARGB(255, 58, 58, 58))), + onPressed: () => Navigator.of(context).pop(false), + ), + CupertinoDialogAction( + child: Text("继续"), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ); + }, + ); + + if (!resFlag!) { + // 提交批注 + return submitTestQuestions(context, currentQuestion!); + } + } + int detailId = theId ?? (isNext ? currentQuestion!.nextId : currentQuestion!.prevId); bool isReview = widget.isReview; @@ -1094,6 +1132,7 @@ class _MarkingPapersState extends ConsumerState // bool flagInputKeyboardGuidePage = await FastData.getInstance().getInputKeyboardGuidePage(); // 引导页标志 try { theRequesting = true; + RestClient client = await getClient(); MarkingTextQuestionTab? temTab; bool isNormal = !widget.exceptional; @@ -1102,8 +1141,6 @@ class _MarkingPapersState extends ConsumerState MarkingTextQuestionTab? oldCurrentTab = _currentTab; temTab = await getTabsData(tabQuestionNum: tabQuestionNum, resetting: resetting); // 切换tag 返回对应的tag - print('当前选中类型:${temTab.questionNum}'); - MarkingTextQuestionTabParams theParam = tabParams.setQuestionNum( tab: temTab, locaQuestionNum: oldCurrentTab?.questionNum, @@ -1130,6 +1167,7 @@ class _MarkingPapersState extends ConsumerState ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG); // 重置批阅痕迹 ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], [])); + currentQuestion = result.data; if (temTab != null) { result.data!.scoreInterval = temTab.scoreInterval ?? 1; @@ -1146,60 +1184,8 @@ class _MarkingPapersState extends ConsumerState imageScale = 1; imagePosition = Offset(0, 0); } - - /** */ - // int? thetypeNum = tabParams.type; - - // // || _currentTab?.total == 0 是因为第一次进入页面 total没有更新造成了total是0 - // if (tabQuestionNum != null || _currentTab?.total == 0) - // await getTabsData(updateCurrentTag: true); // 切换tag更新当前Tag数据 - - // currentQuestion?.scoreInterval = temTab.scoreInterval!; - // if (oldCurrentQuestion == null || - // (oldCurrentQuestion.markingUserDetailId != currentQuestion!.markingUserDetailId)) { - // if (theExamIndex == 0 || tabQuestionNum != null) { - // // 当前试题位置 条件意思代表:当批阅的试题大于等于当前任务并且题池中没有试题 或者 获取当前试题是否继续取题池中的试题(!tabParams.excessContinue) - // theExamIndex = (temTab.finishCount >= temTab.total && temTab.excessCount <= 0) || - // (!tabParams.excessContinue && currentQuestion!.isFinish) - // ? temTab.finishCount - // : temTab.finishCount + 1; // 当前试题的位置 - // } else if (thetypeNum != null) { - // thetypeNum == 0 ? ++theExamIndex : --theExamIndex; - // } - // } - // theExamIndex = currentQuestion?.currentIndex ?? 0; - - /**后端返回当前试题位置不需要前端再去计算位置了 不需要判断超量题和平均量了 */ - // currentQuestion!.setTotalCountAndCurrentIndex( - // temTab.isExcess - // ? (temTab.total > temTab.excessAvgCount ? temTab.total : temTab.excessAvgCount) - // : temTab.total, - // temTab.finishCount); // 设置下标 - - // currentQuestion?.totalCount = temTab.total; } - /** - toUpState(setState, () { - bool hasSub = currentQuestion!.subQuestionDetailList.isNotEmpty; - activeQuestIndex = 0; // 选中题号 - double fullScore; - double getScore; - if (hasSub) { - SubQuestions questions = currentQuestion!.subQuestionDetailList[activeQuestIndex]; - bool isFinish = questions.isFinish; - fullScore = questions.subQuestionScore; - getScore = isFinish ? questions.subQuestionGotScore! : 0; - } else { - fullScore = currentQuestion!.totalScore; - bool isFinish = currentQuestion!.isFinish; // 是否提交 - getScore = isFinish ? currentQuestion!.score! : 0; - } - questScore = getScore == 0 ? '' : getScore.toString(); // 打分值 - hasZeroPointFive = getScore >= fullScore || questScore.length > 1; // 是否是满分/是否已经包含小数 - - // inputKeyboardGuidePage = flagInputKeyboardGuidePage; // 引导页标志配置 - }, mounted);*/ bool hasSub = currentQuestion!.subQuestionDetailList.isNotEmpty; activeQuestIndex = 0; // 选中题号 double fullScore; @@ -1239,6 +1225,7 @@ class _MarkingPapersState extends ConsumerState } } + Future.delayed(Duration.zero, () => annotationTips = false); // getMarkingQuestionsErrorInfo return currentQuestion; } catch (e) { @@ -1935,6 +1922,10 @@ class _MarkingPapersState extends ConsumerState commentImageMap: data.commentImageUrlMap, testQuestionNumber: widget.markingUserId.toString() + '-' + data.questionNum, imageItems: data.studentAnswerList, + callAnnotationTips: () { + // 批注记录被更改 + annotationTips = true; + }, ), ), From 8287518fc18aa2f6509871ca99cfd2af9ea3b5d8 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 15 May 2024 14:00:37 +0800 Subject: [PATCH 12/15] no message --- .../model/marking/marking_text_question.dart | 2 +- .../lib/components/PictureOverview.dart | 3 +- marking_app/lib/pages/mainPage.dart | 2 +- .../lib/provider/upload_file_provider.dart | 35 ++++++++++++------- .../lib/utils/request/rest_client.dart | 4 +++ 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/marking_app/lib/common/model/marking/marking_text_question.dart b/marking_app/lib/common/model/marking/marking_text_question.dart index 12adc1c..d917720 100644 --- a/marking_app/lib/common/model/marking/marking_text_question.dart +++ b/marking_app/lib/common/model/marking/marking_text_question.dart @@ -146,7 +146,7 @@ class MarkingTextQuestion extends Object { for (var i = 0; i < commentImageUrl.length; i++) { var element = commentImageUrl[i]; var originalImage = studentAnswerList[i]; - commentImageUrlMap[originalImage] = '$element?${DateTime.now().millisecondsSinceEpoch}'; + commentImageUrlMap[originalImage] = 'https:$element?${DateTime.now().millisecondsSinceEpoch}'; } } else { for (var element in studentAnswerList) { diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 8bb4258..d9e4fb4 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -216,7 +216,8 @@ class PictureOverviewState extends ConsumerState with CommonMix crypto.Digest fileMd5 = crypto.md5.convert(await temFile!.readAsBytes()); RestClient _client = await getClient(); - BaseStructureResult resUploadConfig = await _client.getUploadFile(UploadFileInterfaceConfigParams( + + BaseStructureResult resUploadConfig = await _client.getMarkingUploadFile(UploadFileInterfaceConfigParams( fileName: '1.png', fileMd5: fileMd5.toString(), contentLength: temFile!.lengthSync(), diff --git a/marking_app/lib/pages/mainPage.dart b/marking_app/lib/pages/mainPage.dart index 7bea9b9..82c2aed 100644 --- a/marking_app/lib/pages/mainPage.dart +++ b/marking_app/lib/pages/mainPage.dart @@ -107,7 +107,7 @@ class TheMainPageState extends ConsumerState with CommonMixin { } void getAppUpgrade(UserInfo user) async { - // if (!bool.fromEnvironment('dart.vm.product')) return; + if (!bool.fromEnvironment('dart.vm.product')) return; try { showUpgrade = true; if (['18888888888'].contains(user.loginName)) return; diff --git a/marking_app/lib/provider/upload_file_provider.dart b/marking_app/lib/provider/upload_file_provider.dart index 6b85b02..044e6de 100644 --- a/marking_app/lib/provider/upload_file_provider.dart +++ b/marking_app/lib/provider/upload_file_provider.dart @@ -22,8 +22,8 @@ import 'package:marking_app/utils/request/rest_client.dart'; // API -final uploadFileProvider = StateNotifierProvider( - (ref) => UploadFileProviderHandle(UploadImgSecretKey())); +final uploadFileProvider = + StateNotifierProvider((ref) => UploadFileProviderHandle(UploadImgSecretKey())); class UploadFileProviderHandle extends StateNotifier with CommonMixin { // Minio? _minio; @@ -109,24 +109,35 @@ class UploadFileProviderHandle extends StateNotifier with Co Future getUploadFileConfig(UploadFileInterfaceConfig uploadConfig, File fileData) async { Dio dio = Dio(); + dio.options.contentType = null; try { late Response response; final bytes = await fileData.readAsBytes(); if (uploadConfig.uploadMethod == "PUT") { - response = await dio.put(uploadConfig.uploadUri!, - data: Stream.fromIterable(bytes.map((e) => [e])), - options: Options(headers: { + response = await dio.put( + uploadConfig.uploadUri!, + data: Stream.fromIterable(bytes.map((e) => [e])), + options: Options( + contentType: null, + headers: { Headers.contentLengthHeader: bytes.length, // Set the content-length. - HttpHeaders.contentTypeHeader: 'image/png', - })); + // HttpHeaders.contentTypeHeader: 'image/png', + }, + ), + ); } else if (uploadConfig.uploadMethod == "POST") { - response = await dio.post(uploadConfig.uploadUri!, - data: Stream.fromIterable(bytes.map((e) => [e])), - options: Options(headers: { + response = await dio.post( + uploadConfig.uploadUri!, + data: Stream.fromIterable(bytes.map((e) => [e])), + options: Options( + contentType: null, + headers: { Headers.contentLengthHeader: bytes.length, // Set the content-length. - HttpHeaders.contentTypeHeader: 'image/png', - })); + // HttpHeaders.contentTypeHeader: 'image/png', + }, + ), + ); } print('文件上传成功:${response.data}'); if ([200, 201, 204].contains(response.statusCode)) { diff --git a/marking_app/lib/utils/request/rest_client.dart b/marking_app/lib/utils/request/rest_client.dart index ac772d0..a6a81d8 100644 --- a/marking_app/lib/utils/request/rest_client.dart +++ b/marking_app/lib/utils/request/rest_client.dart @@ -190,6 +190,10 @@ abstract class RestClient { @the_retrofit.GET("/api/marking/rating-info") Future>> getMarkingRatingInfo(@the_retrofit.Query("markingUserId") int id); + // 阅卷 => 上传图片请求参数 + @the_retrofit.GET("/api/Upload") + Future> getMarkingUploadFile(@the_retrofit.Queries() UploadFileInterfaceConfigParams params); + // ------------------------------------------ 作业 ------------------------------------------ // 作业 => 作业列表 From 1f2e5dbb5684197cfd6d444ccc1d1498d0a74fcd Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Fri, 17 May 2024 15:41:04 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E5=AE=8C=E6=88=90=20=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=9B=B4=E6=94=B9=E5=92=8C=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E7=AC=94=E8=BF=B9=E8=BF=98=E5=8E=9F=E9=BB=98=E8=AE=A4=E4=B8=A4?= =?UTF-8?q?=E5=80=8D=E9=80=9F=20=E5=92=8C=E6=9F=A5=E7=9C=8B=E5=8E=9F?= =?UTF-8?q?=E7=A8=BF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/job/gesture_recording.dart | 8 + .../components/trajectoryView.dart | 2 +- .../pages/homework_correction/job_home.dart | 649 +++++++++++++++++- ...ndwriting_drawing_trajectory_provider.dart | 12 + .../widget/answer_handwriting.dart | 345 ++++++---- 5 files changed, 850 insertions(+), 166 deletions(-) diff --git a/marking_app/lib/common/model/job/gesture_recording.dart b/marking_app/lib/common/model/job/gesture_recording.dart index 5e36be8..f021a6e 100644 --- a/marking_app/lib/common/model/job/gesture_recording.dart +++ b/marking_app/lib/common/model/job/gesture_recording.dart @@ -41,3 +41,11 @@ class GestureHandwritingRecording { required this.intervalTime, }); } + +/** + * 笔记还原页面 查看原稿 + */ +class ShowStudentMmanuscript { + bool showManuscript; // 查看原稿 + ShowStudentMmanuscript(this.showManuscript); +} diff --git a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart index c940af3..2ce7669 100644 --- a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart +++ b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart @@ -224,7 +224,7 @@ class TrajectoryViewState extends ConsumerState { var zhixinCall = () async { if (mounted) { - print('执行添加笔画${i},${j}'); + // print('执行添加笔画${i},${j}'); trajectorys = List.from(trajectorys)..add(theRecording); ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys); } diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index 9e067a7..9492963 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -1,19 +1,568 @@ +// import 'package:flutter/material.dart'; +// import 'package:flutter/services.dart'; +// import 'package:flutter_hooks/flutter_hooks.dart'; +// import 'package:flutter_screenutil/flutter_screenutil.dart'; +// import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +// import 'package:marking_app/common/mixin/common.dart'; +// import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart'; +// import 'package:marking_app/common/model/marking/marking_list_params.dart'; +// import 'package:marking_app/pages/common/event_bus_mixin.dart'; +// import 'package:marking_app/routes/RouterManager.dart'; +// import 'package:marking_app/utils/index.dart'; +// import 'package:marking_app/utils/my_text.dart'; +// import 'package:flutter_easyrefresh/easy_refresh.dart'; + +// import 'package:badges/badges.dart' as badges; + +// part 'job_home.g.dart'; + +// class JobHome extends StatefulWidget { +// const JobHome({super.key}); + +// @override +// State createState() => _JobHomeState(); +// } + +// class _JobHomeState extends State with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin { +// @override +// bool get wantKeepAlive => true; + +// late LinkHeaderNotifier _linkNotifier; +// late ValueNotifier _secondFloorOpen; + +// @override +// void initState() { +// getData(); +// eventOn(callback: (JobHomeRefreshBus item) => getData()); +// _linkNotifier = LinkHeaderNotifier(); +// _secondFloorOpen = ValueNotifier(false); +// super.initState(); +// } + +// @override +// void dispose() { +// eventCancel(); +// _linkNotifier.dispose(); +// _secondFloorOpen.dispose(); +// super.dispose(); +// } + +// Future getData() async { +// try { +// var _client = await getClient(); +// var _result = await _client.getJobsByPage(MarkingListParams( +// isFinish: false, +// page: 1, +// limit: 1, +// pageType: 0, +// )); +// var data = _result.data?.total ?? 0; +// eventFire(model: QuantityToBeReviewedData(data)); +// return data; +// } catch (e) { +// return 0; +// } +// } + +// @override +// Widget build(BuildContext context) { +// super.build(context); + +// return AnnotatedRegion( +// value: const SystemUiOverlayStyle( +// systemNavigationBarColor: Color(0xFF000000), +// systemNavigationBarDividerColor: null, +// statusBarColor: Colors.white, +// systemNavigationBarIconBrightness: Brightness.light, +// statusBarIconBrightness: Brightness.dark, +// statusBarBrightness: Brightness.light, +// ), +// child: SizedBox( +// height: ScreenUtil().screenHeight, +// width: ScreenUtil().screenWidth, +// child: Column( +// children: [ +// // 二楼 +// SecondFloorWidget(_linkNotifier, _secondFloorOpen, refreshCall: () => eventFire(model: JobHomeRefreshBus())), +// Expanded( +// child: EasyRefresh.custom( +// header: LinkHeader( +// _linkNotifier, +// extent: 70.0, +// triggerDistance: 70.0, +// completeDuration: Duration(milliseconds: 500), +// ), +// onRefresh: () async { +// if (_secondFloorOpen.value) return; +// // await Future.delayed(Duration(seconds: 2), () { +// // if (mounted) { +// // setState(() { +// // _count = 20; +// // }); +// // } +// // }); +// }, +// onLoad: () async { +// // await Future.delayed(Duration(seconds: 2), () { +// // if (mounted) { +// // setState(() { +// // _count += 20; +// // }); +// // } +// // }); +// }, +// slivers: [ +// SliverAppBar( +// expandedHeight: 300.h, +// pinned: true, +// floating: true, +// backgroundColor: Colors.red, +// flexibleSpace: FlexibleSpaceBar( +// centerTitle: false, +// title: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SlidingData([ +// EntranceModel( +// title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath), +// EntranceModel( +// title: '学生历史作业', +// image: 'assets/images/job_home_history.png', +// navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history', +// ), +// EntranceModel( +// title: '知识点点掌握', +// image: 'assets/images/job_home_knowledge.png', +// navigationUrl: RouterManager.jobKnowledgePointsPath) +// ]), +// $TermRow([ +// EntranceModel( +// title: '答题轨迹', +// image: 'assets/images/job_home_answer_record.png', +// navigationUrl: RouterManager.answerTrajectoryPath), +// EntranceModel( +// title: '优先批阅设定', +// image: 'assets/images/job_home_youxian.png', +// navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set', +// ) +// ], 0), +// ], +// )), +// ), +// SliverList( +// delegate: SliverChildBuilderDelegate( +// (context, index) { +// return Container( +// height: 40.h, +// color: Colors.amber, +// width: ScreenUtil().screenWidth, +// ); +// }, +// childCount: 10, +// ), +// ), +// ], +// ), +// ), +// ], +// ), +// )); +// } +// } + +// class EntranceModel extends Object { +// String title; +// String image; +// String navigationUrl; +// EntranceModel({required this.title, required this.image, required this.navigationUrl}); +// } + +// class QuantityToBeReviewedData extends Object { +// int num; +// QuantityToBeReviewedData(this.num); +// } + +// @swidget +// Widget $termRow(BuildContext context, List items, int data) { +// var leng = items.length; +// Widget childWidget; +// switch (leng) { +// case 1: +// childWidget = Row(children: [Expanded(child: $TermItem(items[0], data))]); +// break; +// case 2: +// childWidget = Row(children: [ +// Expanded(flex: 9, child: $TermItem(items[0], data)), +// Expanded(flex: 1, child: SizedBox()), +// Expanded(flex: 9, child: $TermItem(items[1], data)), +// ]); +// break; +// case 3: +// double _theHeight = ScreenUtil().screenWidth / 19 + 54.h * 2; +// childWidget = Row( +// children: [ +// Expanded(child: $TermItem(items[0], data, theHeight: _theHeight)), +// SizedBox(width: ScreenUtil().screenWidth / 19), +// Expanded( +// child: SizedBox( +// height: _theHeight, +// child: Column( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// $TermItem(items[1], data), +// $TermItem(items[2], data), +// ], +// ), +// ), +// ), +// ], +// ); +// break; +// default: +// childWidget = Container(); +// } + +// return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget); +// } + +// @swidget +// Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) { +// bool isJob = e.title == '作业批阅'; + +// return Material( +// color: Colors.white, +// elevation: 3.r, +// shadowColor: const Color.fromRGBO(231, 231, 231, 1), +// borderRadius: BorderRadius.all(Radius.circular(8.r)), +// child: InkWell( +// onTap: () => easyThrottle('GO_TO_JOB_HOME_NAVIGATION', () { +// RouterManager.router.navigateTo(context, e.navigationUrl, transition: getTransition()); +// }), + +// // splashColor: splashColor, +// borderRadius: BorderRadius.all(Radius.circular(8.r)), +// child: badges.Badge( +// showBadge: isJob && data > 0, +// ignorePointer: false, +// badgeContent: quickText(data, color: Colors.white, size: 10.sp), +// badgeAnimation: badges.BadgeAnimation.rotation( +// animationDuration: Duration(seconds: 1), +// colorChangeAnimationDuration: Duration(seconds: 1), +// loopAnimation: false, +// curve: Curves.fastOutSlowIn, +// colorChangeAnimationCurve: Curves.easeInCubic, +// ), +// badgeStyle: badges.BadgeStyle( +// badgeColor: Color.fromRGBO(255, 105, 105, 1), +// shape: badges.BadgeShape.square, +// borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)), +// // borderSide: BorderSide(color: Colors.white, width: 2), +// elevation: 1, +// padding: EdgeInsets.symmetric(horizontal: isPad() ? 11.w : 16.w, vertical: 2.h), +// ), +// position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r), +// child: Container( +// height: theHeight, +// padding: EdgeInsets.symmetric(vertical: 12.h), +// decoration: BoxDecoration( +// borderRadius: BorderRadius.all(Radius.circular(8.r)), +// // boxShadow: [ +// // BoxShadow( +// // color: const Color.fromRGBO(231, 231, 231, 1), +// // offset: Offset(4.w, 6.h), //阴影y轴偏移量 +// // blurRadius: 8, //阴影模糊程度 +// // spreadRadius: 0.2, //阴影扩散程度 +// // ) +// // ], +// // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)), +// ), +// alignment: Alignment.center, +// child: isJob +// ? Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), +// SizedBox(height: 6.r), +// quickText(e.title, size: 12.sp, color: Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), +// ], +// ) +// : Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), +// SizedBox(width: 6.r), +// quickText(e.title, size: 12.sp, color: Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), +// ], +// ), +// ), +// )), +// ); +// } + +// class SlidingData extends HookWidget with EventBusMixin { +// final List items; +// SlidingData(this.items); + +// @override +// Widget build(BuildContext context) { +// var dataNumber = useState(null); + +// useEffect(() { +// eventOn(callback: (QuantityToBeReviewedData data) => (dataNumber.value = data)); +// return () { +// eventCancel(); +// }; +// }, []); + +// return $TermRow(items, dataNumber.value?.num ?? 0); +// } +// } + +// /// 二楼视图 +// class SecondFloorWidget extends StatefulWidget { +// // Header连接通知器 +// final LinkHeaderNotifier linkNotifier; +// // 二楼开启状态 +// final ValueNotifier secondFloorOpen; +// final Function refreshCall; + +// const SecondFloorWidget(this.linkNotifier, this.secondFloorOpen, {required this.refreshCall, Key? key}) : super(key: key); + +// @override +// State createState() => SecondFloorWidgetState(); +// } + +// class SecondFloorWidgetState extends State { +// // 触发二楼高度 +// final double _openSecondFloorExtent = 100.0; +// // 指示器值 +// double? _indicatorValue = 0.0; + +// // 二楼高度 +// double _secondFloor = 0.0; +// // 显示展开收起动画 +// bool _toggleAnimation = false; +// Duration _toggleAnimationDuration = Duration(milliseconds: 300); +// // 二楼是否打开 +// bool _isOpen = false; + +// RefreshMode get _refreshState => widget.linkNotifier.refreshState; +// double get _pulledExtent => widget.linkNotifier.pulledExtent; + +// @override +// void initState() { +// widget.linkNotifier.addListener(onLinkNotify); +// super.initState(); +// } + +// void onLinkNotify() { +// setState(() { +// if (_refreshState == RefreshMode.armed || _refreshState == RefreshMode.refresh) { +// _indicatorValue = null; +// // 判断是否到展开二楼 +// if (widget.secondFloorOpen.value && !_toggleAnimation) { +// _isOpen = true; +// _secondFloor = MediaQuery.of(context).size.height - 60.h; +// _toggleAnimation = true; +// Future.delayed(_toggleAnimationDuration, () { +// if (mounted) { +// setState(() { +// _toggleAnimation = false; +// }); +// } +// }); +// } +// } else if (_refreshState == RefreshMode.refreshed || _refreshState == RefreshMode.done) { +// _indicatorValue = 1.0; +// } else { +// if (_refreshState == RefreshMode.inactive) { +// _indicatorValue = 0.0; +// _toggleAnimation = true; +// Future.delayed(_toggleAnimationDuration, () { +// if (mounted) { +// setState(() { +// _toggleAnimation = false; +// }); +// } +// }); +// } else { +// double indicatorValue = _pulledExtent / 70.0 * 0.8; +// _indicatorValue = indicatorValue < 0.8 ? indicatorValue : 0.8; +// // 判断是否到达打开二楼高度 +// if (_refreshState == RefreshMode.drag) { +// if (_pulledExtent >= _openSecondFloorExtent) { +// widget.secondFloorOpen.value = true; +// } else { +// widget.secondFloorOpen.value = false; +// } +// } +// } +// } +// }); +// } + +// @override +// Widget build(BuildContext context) { +// // var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19); +// // return RefreshIndicator( +// // onRefresh: () async => widget.refreshCall(), +// // child: ListView( +// // children: [ +// // Container( +// // constraints: BoxConstraints( +// // minHeight: 200.h, +// // maxWidth: double.infinity, +// // ), +// // child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth), +// // ), +// // SizedBox(height: 30.h), +// // SlidingData([ +// // EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath), +// // EntranceModel( +// // title: '学生历史作业', +// // image: 'assets/images/job_home_history.png', +// // navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history', +// // ), +// // EntranceModel(title: '知识点点掌握', image: 'assets/images/job_home_knowledge.png', navigationUrl: RouterManager.jobKnowledgePointsPath) +// // ]), +// // spaceWidth, +// // $TermRow([ +// // EntranceModel(title: '答题轨迹', image: 'assets/images/job_home_answer_record.png', navigationUrl: RouterManager.answerTrajectoryPath), +// // EntranceModel( +// // title: '优先批阅设定', +// // image: 'assets/images/job_home_youxian.png', +// // navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set', +// // ) +// // ], 0), +// // // spaceWidth, +// // // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), +// // ], +// // ), +// // ); +// var heightVal = _isOpen +// ? _secondFloor +// : _refreshState == RefreshMode.inactive +// ? 0.0 +// : _pulledExtent; +// return AnnotatedRegion( +// value: const SystemUiOverlayStyle( +// systemNavigationBarColor: Color(0xFF000000), +// systemNavigationBarDividerColor: null, +// statusBarColor: Colors.white, +// systemNavigationBarIconBrightness: Brightness.light, +// statusBarIconBrightness: Brightness.dark, +// statusBarBrightness: Brightness.light, +// ), +// child: InkWell( +// onTap: () { +// if (_isOpen) { +// setState(() { +// _isOpen = false; +// _toggleAnimation = true; +// Future.delayed(_toggleAnimationDuration, () { +// if (mounted) { +// setState(() { +// _toggleAnimation = false; +// }); +// } +// }); +// }); +// } +// }, +// child: AnimatedContainer( +// padding: EdgeInsets.zero, +// height: heightVal, +// color: Colors.white, +// duration: _toggleAnimation ? _toggleAnimationDuration : Duration(milliseconds: 1), +// child: Stack( +// children: [ +// Positioned( +// bottom: 0.0, +// left: 0.0, +// right: 0.0, +// child: Container( +// height: MediaQuery.of(context).size.height, +// width: double.infinity, +// child: Image.asset( +// 'assets/images/job_home_top_bgm.png', +// fit: BoxFit.fitHeight, +// ), +// ), +// ), +// Positioned( +// bottom: 0.0, +// left: 0.0, +// right: 0.0, +// child: AnimatedCrossFade( +// firstChild: Center( +// child: Container( +// alignment: Alignment.center, +// margin: EdgeInsets.only( +// bottom: 20.0, +// top: 10.0, +// ), +// width: 24.0, +// height: 24.0, +// child: Offstage( +// offstage: widget.secondFloorOpen.value, +// child: CircularProgressIndicator( +// value: _indicatorValue, +// valueColor: AlwaysStoppedAnimation(Colors.white), +// strokeWidth: 2.4, +// ), +// ), +// ), +// ), +// secondChild: Center( +// child: Container( +// alignment: Alignment.center, +// margin: EdgeInsets.only( +// bottom: 20.0, +// top: 10.0, +// ), +// child: Offstage( +// offstage: !widget.secondFloorOpen.value, +// child: Text( +// '欢迎来到二楼', +// style: TextStyle(fontSize: 18.0, color: Colors.white), +// ), +// ), +// ), +// ), +// crossFadeState: widget.secondFloorOpen.value ? CrossFadeState.showSecond : CrossFadeState.showFirst, +// duration: Duration(milliseconds: 300), +// ), +// ), +// ], +// ), +// ), +// ), +// ); +// } +// } + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_page_data.dart'; import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart'; +import 'package:marking_app/common/model/job/job_task_item.dart'; import 'package:marking_app/common/model/marking/marking_list_params.dart'; import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; +import 'package:marking_app/utils/easy_refresh/mixin/refresh_data_handle.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; import 'package:badges/badges.dart' as badges; +import 'package:marking_app/utils/request/rest_client.dart'; -import '../../utils/my_future_builder.dart'; +import 'components/new_version_of_homework/homework_tasks_view_item.dart'; part 'job_home.g.dart'; @@ -24,37 +573,51 @@ class JobHome extends StatefulWidget { State createState() => _JobHomeState(); } -class _JobHomeState extends State with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin { +class _JobHomeState extends State + with CommonMixin, EventBusMixin, RefreshDataHandle, AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; + var param = MarkingListParams(isFinish: false, page: 1, limit: 1, pageType: 0); + + int totalJobNumber = 0; + List jobDatas = []; + late final EasyRefreshController _refreshController; + @override void initState() { - getData(); - eventOn(callback: (JobHomeRefreshBus item) => getData()); + _refreshController = EasyRefreshController(); super.initState(); } @override void dispose() { + _refreshController.dispose(); eventCancel(); super.dispose(); } - Future getData() async { - try { - var _client = await getClient(); - var _result = await _client.getJobsByPage(MarkingListParams( - isFinish: false, - page: 1, - limit: 1, - pageType: 0, - )); - var data = _result.data?.total ?? 0; - eventFire(model: QuantityToBeReviewedData(data)); - return data; - } catch (e) { - return 0; + /* 发起请求 => 作业 */ + Future toGetPageData({bool isReFresh = false}) async { + if (!isReFresh) { + param.page++; + } + RestClient client = await getClient(); + BasePageData? results = await toRefreshData( + _refreshController, + api: client.getJobsByPage, + params: param, + isReFresh: isReFresh, + context: context, + ); + if (results != null) { + Future.delayed(Duration(seconds: 1), () => eventFire(model: QuantityToBeReviewedData(results.total))); + if (isReFresh) { + jobDatas.clear(); + jobDatas = results.items; + } else + jobDatas.addAll(results.items); + setState(() {}); } } @@ -71,24 +634,31 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto statusBarIconBrightness: Brightness.dark, statusBarBrightness: Brightness.light, ), - child: RefreshIndicator( - onRefresh: () async => eventFire(model: JobHomeRefreshBus()), + child: EasyRefresh( + firstRefresh: true, + taskIndependence: true, + enableControlFinishLoad: true, + enableControlFinishRefresh: true, + emptyWidget: jobDatas.isEmpty ? const MyEmptyWidget() : null, + controller: _refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), child: ListView( children: [ - Container( - constraints: BoxConstraints( - minHeight: 200.h, - maxWidth: double.infinity, - ), - // decoration: BoxDecoration( - // image: DecorationImage( - // image: AssetImage('assets/images/job_home_top_bgm.png'), - // fit: BoxFit.fitWidth, // 完全填充 - // ), - // ), - child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth), - ), - SizedBox(height: 30.h), + // Container( + // constraints: BoxConstraints( + // minHeight: 200.h, + // maxWidth: double.infinity, + // ), + // // decoration: BoxDecoration( + // // image: DecorationImage( + // // image: AssetImage('assets/images/job_home_top_bgm.png'), + // // fit: BoxFit.fitWidth, // 完全填充 + // // ), + // // ), + // child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth), + // ), + SizedBox(height: MediaQuery.of(context).padding.top + 20.h), SlidingData([ EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath), EntranceModel( @@ -109,8 +679,19 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto ], 0), // spaceWidth, // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), + spaceWidth, + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w), + child: Column( + children: jobDatas + .map((e) => HomeworkTasksViewItem(completed: false, jobTaskItem: e, call: () => _refreshController.callRefresh())) + .toList(), + ), + ) ], ), + onRefresh: () => toGetPageData(isReFresh: true), + onLoad: () => toGetPageData(isReFresh: false), ), ); } diff --git a/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart index 30f40bf..f03b826 100644 --- a/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart +++ b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart @@ -16,3 +16,15 @@ class JobHandwritingDrawingTrajectoryProviderHandle extends StateNotifier( + (ref) => JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript(false))); + +class JobHandwritingStudentManuscriptHandle extends StateNotifier { + JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript progress) : super(progress); + + setVal(ShowStudentMmanuscript val) { + state = val; + } +} diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index e3d77e6..34cb1e4 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -375,19 +375,35 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev late ImageStreamListener theImageStreamListener; late ValueNotifier> _vnHandWritings; + late ValueNotifier> _vnPrimaryHandWritings; late RemoveListener _jobHandwritingDrawingTrajectoryListener; // 批注关闭监听 + late RemoveListener _jobHandwritingDrawingTrajectoryListener1; // 查看原稿 List> _packagedHandwritingDatas = []; - List _packagedHandwritingDataAll = []; + List _packagedHandwritingDataAll = []; // 总数据 List pendingData = []; // 待执行数据 List timers = []; int handwritingTime = 0; int handwritingDuration = 0; - double speed = 1; // 播放速度 + double speed = 2.0; // 播放速度 + @override void initState() { super.initState(); _vnHandWritings = ValueNotifier>([]); + _vnPrimaryHandWritings = ValueNotifier>([]); + _jobHandwritingDrawingTrajectoryListener1 = ref.read(jobHandwritingStudentManuscriptProvider.notifier).addListener((state) { + print('点击进入了'); + // 查看原稿控制 + if (state.showManuscript) { + // 查看原稿 + eventFire(model: JobHandwritingPlaybarBus(false)); // 暂停 + _vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll]; + } else { + // 清空原稿数据 + _vnPrimaryHandWritings.value = []; + } + }, fireImmediately: false); _jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) { _vnHandWritings.value = state; }, fireImmediately: false); @@ -447,7 +463,9 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev if (e.isActive) e.cancel(); }); _jobHandwritingDrawingTrajectoryListener(); + _jobHandwritingDrawingTrajectoryListener1(); _vnHandWritings.dispose(); + _vnPrimaryHandWritings.dispose(); try { imageStream?.removeListener(theImageStreamListener); eventCancel(); @@ -537,7 +555,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev pendingData.addAll(_packagedHandwritingDataAll); ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); } - + ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(false)); executableData.forEach((e) { var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e)); timers.add(ter); @@ -579,14 +597,12 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev @override Widget build(BuildContext context) { + var showManuscript = ref.watch(jobHandwritingStudentManuscriptProvider).showManuscript; return Container( alignment: Alignment.center, child: RepaintBoundary( child: CustomPaint( - willChange: true, - isComplex: true, - foregroundPainter: HandWritingDrawingPainter(ctrl: _vnHandWritings), - // size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight), + foregroundPainter: HandWritingDrawingPainter(ctrl: showManuscript ? _vnPrimaryHandWritings : _vnHandWritings), child: RepaintBoundary( child: $TheCachedNetworkImage( imageUrl: widget.image, @@ -609,6 +625,47 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev } } +class HandWritingDrawingPainter1 extends CustomPainter { + final ValueNotifier> ctrl; + HandWritingDrawingPainter1({required this.ctrl}) : super(repaint: ctrl); + //[定义画笔] + final Paint paintBrush = Paint() + //画笔颜色 + ..color = Colors.black + //画笔笔触类型 + ..strokeCap = StrokeCap.round + //是否启动抗锯齿 + ..isAntiAlias = true + //绘画风格,默认为填充 + // ..style = PaintingStyle.fill + //画笔的宽度 + ..style = PaintingStyle.stroke + ..strokeWidth = 0.5.r; + + @override + void paint(Canvas canvas, Size size) { + // canvas.drawPoints(PointMode.points, thePoints, paintBrush); + + var points = ctrl.value; + var _length = points.length; + for (int i = 0; i < _length; i++) { + GestureHandwritingRecording item = points[i]; + GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null; + + Offset offsetData = item.data; + Offset? nextOffsetData = nextItem?.data; + if (nextOffsetData != null && item.stroke == nextItem?.stroke) { + canvas.drawLine(offsetData, nextOffsetData, paintBrush); + } + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; // 如果 oldDelegate 不是 MyCustomPainter 的实例,则总是重绘 + } +} + class HandWritingDrawingPainter extends CustomPainter { final ValueNotifier> ctrl; HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl); @@ -746,148 +803,174 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L }, []); return Container( - height: 60.h, + height: 62.h, padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), alignment: Alignment.center, color: Color.fromRGBO(0, 0, 0, 0.4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - if (usePlaybar.handWritingReady.value) - InkWell( - onTap: () => easyThrottle('job_handwriting_play_pause', () { - if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹'); + Container(alignment: Alignment.centerRight, child: StudentManuscriptBtn()), // 查看原稿按钮 + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (usePlaybar.handWritingReady.value) + InkWell( + onTap: () => easyThrottle('job_handwriting_play_pause', () { + if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹'); - usePlaybar.playPause.value = !usePlaybar.playPause.value; - usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); - }), - child: Icon( - !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline, - color: Colors.white, - size: 28.r, - ), - ) - else - SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), - SizedBox(width: 6.w), - Expanded( - child: LayoutBuilder(builder: (context, constraints) { - final double containerWidth = constraints.maxWidth; // 展示区域总宽度 - var unitScale = containerWidth / timeConsuming; // 单位刻度 - var pauseIntervalsLength = pauseIntervals.length; - - List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { - bool isLast = e == pauseIntervalsLength - 1; - bool isFirst = e == 0; - var item = pauseIntervals[e]; - return Positioned( - top: 0, - left: unitScale * item.startTime, - child: Container( - width: unitScale * (item.apart ?? 0), - height: 8.h, - decoration: BoxDecoration( - color: Color.fromRGBO(202, 201, 201, 1), - borderRadius: isFirst - ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) - : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), - ), + usePlaybar.playPause.value = !usePlaybar.playPause.value; + usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); + }), + child: Icon( + !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline, + color: Colors.white, + size: 28.r, ), - ); - }).toList(); + ) + else + SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), + SizedBox(width: 6.w), + Expanded( + child: LayoutBuilder(builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + var unitScale = containerWidth / timeConsuming; // 单位刻度 + var pauseIntervalsLength = pauseIntervals.length; - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - children: [ - Container( + List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = pauseIntervals[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), height: 8.h, - width: containerWidth, decoration: BoxDecoration( - // color: Color.fromRGBO(146, 146, 146, 1), - color: Colors.white, - borderRadius: BorderRadius.circular(50.r), + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: isFirst + ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) + : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), ), ), - ...pauseTickMarks, - Container( - height: 8.h, + ); + }).toList(); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Container( + height: 8.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Colors.white, + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 8.h, + width: containerWidth, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 8.h, // 轨道高度 + trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + SizedBox( width: containerWidth, - // color: Theme.of(context).primaryColor, - child: SliderTheme( - data: SliderTheme.of(context).copyWith( - trackHeight: 8.h, // 轨道高度 - trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 - activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 - inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), - thumbColor: Colors.white, // 滑块颜色 - overlayShape: RoundSliderOverlayShape(overlayRadius: 0), - overlayColor: Colors.black54, // 滑块外圈颜色 - // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 - ), - child: Slider( - value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), - min: 0.0, - max: usePlaybar.handwritingDuration.value.toDouble(), - inactiveColor: Colors.transparent, - onChangeEnd: (value) { - if (!usePlaybar.handWritingReady.value) return; - usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 - usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - onChanged: (double value) { - if (!usePlaybar.handWritingReady.value) return; - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), + quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + ], ), - ), + ) ], - ), - SizedBox(height: 4.h), - SizedBox( - width: containerWidth, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), - quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), - ], - ), - ) - ], - ); - }), - ), - SizedBox(width: 16.w), - InkWell( - onTap: () => easyThrottle('job_handwriting_speed', () { - var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value); - if (theIndex == PlaybackSpeed.values.length - 1) { - theIndex = -1; - } - usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1]; - }, duration: Duration(milliseconds: 500)), - child: Container( - // alignment: Alignment., - padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), - decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), - child: quickText( - '${usePlaybar.constantFastSpeed.value.name}', - color: Color.fromRGBO(79, 114, 244, 1), - size: 8.sp, - align: TextAlign.center, + ); + }), ), - ), - ), + SizedBox(width: 16.w), + InkWell( + onTap: () => easyThrottle('job_handwriting_speed', () { + var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value); + if (theIndex == PlaybackSpeed.values.length - 1) { + theIndex = -1; + } + usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1]; + }, duration: Duration(milliseconds: 500)), + child: Container( + // alignment: Alignment., + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), + child: quickText( + '${usePlaybar.constantFastSpeed.value.name}', + color: Color.fromRGBO(79, 114, 244, 1), + size: 8.sp, + align: TextAlign.center, + ), + ), + ), + ], + ) ], ), ); } +// 学生原稿按钮视图 +class StudentManuscriptBtn extends ConsumerWidget { + const StudentManuscriptBtn({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return InkWell( + onTap: () => easyThrottle('job_handwriting_udent_manuscript', () { + var showManuscript = ref.read(jobHandwritingStudentManuscriptProvider).showManuscript; + ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(!showManuscript)); + }), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 1.h), + decoration: BoxDecoration(color: Colors.grey, borderRadius: BorderRadius.circular(4.r)), + child: quickText('学生原稿', color: Colors.white, size: 8.sp), + ), + ); + } +} + class SysjTime extends StatefulWidget { const SysjTime({super.key}); @@ -921,7 +1004,7 @@ class _SysjTimeState extends State with EventBusMixin handwritingDuration; // 笔迹总时长 final ValueNotifier playPause; // 播放暂停 - final ValueNotifier constantFastSpeed; // 原速、快速 默认原速 + final ValueNotifier constantFastSpeed; // 播放速度 final ValueNotifier handWritingReady; final ValueNotifier useTime; // 耗时 单位:(秒) @@ -942,7 +1025,7 @@ class UseBottomPlaybar with EventBusMixin { if ((milliseconds % 1000) > 500) handwritingDuration += 1; return UseBottomPlaybar._( playPause: useState(false), - constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED), + constantFastSpeed: useState(PlaybackSpeed.DOUBLE_SPEED), // 默认两倍速 useTime: useState(handwritingDuration), timer: useState(null), handwritingDuration: useState(handwritingDuration), From c955f1859a9ef711097a8bcae39d5aca739f9fb2 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 20 May 2024 10:48:12 +0800 Subject: [PATCH 14/15] no message --- marking_app/lib/components/TestPaperItem.dart | 27 +++------ .../pages/homework_correction/job_home.dart | 59 ++++++++++++------- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/marking_app/lib/components/TestPaperItem.dart b/marking_app/lib/components/TestPaperItem.dart index 813c8f1..4293660 100644 --- a/marking_app/lib/components/TestPaperItem.dart +++ b/marking_app/lib/components/TestPaperItem.dart @@ -29,9 +29,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { final bool isHomeworkCorrection; final VoidCallback? call; final MarkingListType? markingtype; - const TestPaperItem( - {required this.markingItem, this.markingtype, this.isHomeworkCorrection = false, this.call, Key? key}) - : super(key: key); + const TestPaperItem({required this.markingItem, this.markingtype, this.isHomeworkCorrection = false, this.call, Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { @@ -65,7 +63,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h), constraints: BoxConstraints( minHeight: 120.h, - maxHeight: 130.h, + maxHeight: 144.h, ), decoration: BoxDecoration( color: Colors.white, @@ -117,8 +115,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { margin: EdgeInsets.only(right: 8.w), alignment: Alignment.center, decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), color: const Color.fromRGBO(245, 108, 108, 0.236), ), child: Text( @@ -137,8 +134,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { margin: EdgeInsets.only(right: 8.w), alignment: Alignment.center, decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), color: const Color.fromRGBO(4, 201, 208, 0.10), ), child: Text( @@ -157,8 +153,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { margin: EdgeInsets.only(right: 8.w), alignment: Alignment.center, decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), color: const Color.fromRGBO(231, 236, 255, 1), ), child: Text( @@ -270,10 +265,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { Text( '${markingItem.finishCount}', style: TextStyle( - color: markingItem.isFinish && isHomeworkCorrection - ? Colors.green - : Theme.of(context).primaryColor, - fontSize: 12.sp), + color: markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor, fontSize: 12.sp), ), Text( '/', @@ -299,8 +291,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { style: TextStyle(color: Colors.white, fontSize: 8.sp), ), // linearStrokeCap: LinearStrokeCap.butt, - progressColor: - markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor, + progressColor: markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor, backgroundColor: const Color.fromRGBO(219, 224, 243, 1), barRadius: Radius.circular(10.r), ), @@ -503,9 +494,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin { RestClient client = await getClient(); BaseStructureResult result = await client.endMarkingTask(markingUserId); if (result.code == RequestConfig.successCode && result.data == null ? false : result.data!) { - ref - .read(currentTaskIdProvider.notifier) - .setDoTaskEntity(CurrentReviewTask(taskId: markingItem.markingUserId, refresh: true)); + ref.read(currentTaskIdProvider.notifier).setDoTaskEntity(CurrentReviewTask(taskId: markingItem.markingUserId, refresh: true)); } else { ToastUtils.getFluttertoast(context: context, msg: '提交失败'); } diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index 9492963..c144930 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -624,7 +624,7 @@ class _JobHomeState extends State @override Widget build(BuildContext context) { super.build(context); - var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19); + return AnnotatedRegion( value: const SystemUiOverlayStyle( systemNavigationBarColor: Color(0xFF000000), @@ -639,7 +639,7 @@ class _JobHomeState extends State taskIndependence: true, enableControlFinishLoad: true, enableControlFinishRefresh: true, - emptyWidget: jobDatas.isEmpty ? const MyEmptyWidget() : null, + emptyWidget: jobDatas.isEmpty ? $TheJobMainBox(emptyWidget: MyEmptyWidget()) : null, controller: _refreshController, header: MaterialHeader(), footer: TaurusFooter(), @@ -658,28 +658,10 @@ class _JobHomeState extends State // // ), // child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth), // ), - SizedBox(height: MediaQuery.of(context).padding.top + 20.h), - SlidingData([ - EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath), - EntranceModel( - title: '学生历史作业', - image: 'assets/images/job_home_history.png', - navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history', - ), - EntranceModel(title: '知识点点掌握', image: 'assets/images/job_home_knowledge.png', navigationUrl: RouterManager.jobKnowledgePointsPath) - ]), - spaceWidth, - $TermRow([ - EntranceModel(title: '答题轨迹', image: 'assets/images/job_home_answer_record.png', navigationUrl: RouterManager.answerTrajectoryPath), - EntranceModel( - title: '优先批阅设定', - image: 'assets/images/job_home_youxian.png', - navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set', - ) - ], 0), + $TheJobMainBox(), // spaceWidth, // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), - spaceWidth, + Container( padding: EdgeInsets.symmetric(horizontal: 12.w), child: Column( @@ -844,3 +826,36 @@ class SlidingData extends HookWidget with EventBusMixin { return $TermRow(items, dataNumber.value?.num ?? 0); } } + +// 作业主页 +@swidget +Widget $theJobMainBox(BuildContext context, {Widget? emptyWidget}) { + var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: MediaQuery.of(context).padding.top + 20.h), + SlidingData([ + EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath), + EntranceModel( + title: '学生历史作业', + image: 'assets/images/job_home_history.png', + navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history', + ), + EntranceModel(title: '知识点点掌握', image: 'assets/images/job_home_knowledge.png', navigationUrl: RouterManager.jobKnowledgePointsPath) + ]), + spaceWidth, + $TermRow([ + EntranceModel(title: '答题轨迹', image: 'assets/images/job_home_answer_record.png', navigationUrl: RouterManager.answerTrajectoryPath), + EntranceModel( + title: '优先批阅设定', + image: 'assets/images/job_home_youxian.png', + navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set', + ) + ], 0), + if (emptyWidget != null) emptyWidget, + spaceWidth, + ], + ); +} From bf0a5f5ff14e6567f7489f86ac89e4286a4f0bc0 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 20 May 2024 15:34:14 +0800 Subject: [PATCH 15/15] no message --- marking_app/README.md | 4 + ...ndwriting_drawing_trajectory_provider.dart | 2 +- .../widget/answer_handwriting.dart | 289 ++++++++---------- marking_app/pubspec.yaml | 2 +- 4 files changed, 133 insertions(+), 164 deletions(-) diff --git a/marking_app/README.md b/marking_app/README.md index 0b70d96..7622a87 100644 --- a/marking_app/README.md +++ b/marking_app/README.md @@ -14,3 +14,7 @@ A few resources to get you started if this is your first Flutter project: For help getting started with Flutter development, view the [online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. + + + +fvm flutter build apk --release --no-tree-shake-icons \ No newline at end of file diff --git a/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart index f03b826..de6dfd6 100644 --- a/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart +++ b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart @@ -19,7 +19,7 @@ class JobHandwritingDrawingTrajectoryProviderHandle extends StateNotifier( - (ref) => JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript(false))); + (ref) => JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript(true))); class JobHandwritingStudentManuscriptHandle extends StateNotifier { JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript progress) : super(progress); diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index 34cb1e4..d0921a8 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -391,9 +391,8 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev void initState() { super.initState(); _vnHandWritings = ValueNotifier>([]); - _vnPrimaryHandWritings = ValueNotifier>([]); + _vnPrimaryHandWritings = ValueNotifier>(_packagedHandwritingDataAll); _jobHandwritingDrawingTrajectoryListener1 = ref.read(jobHandwritingStudentManuscriptProvider.notifier).addListener((state) { - print('点击进入了'); // 查看原稿控制 if (state.showManuscript) { // 查看原稿 @@ -590,6 +589,9 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev _packagedHandwritingDatas.add(newTrajectoryData); // 分组数据 _packagedHandwritingDataAll.addAll(newTrajectoryData); // 不分组数据 + try { + Future.delayed(Duration.zero, () => ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(true))); + } catch (e) {} } Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹 } @@ -625,47 +627,6 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev } } -class HandWritingDrawingPainter1 extends CustomPainter { - final ValueNotifier> ctrl; - HandWritingDrawingPainter1({required this.ctrl}) : super(repaint: ctrl); - //[定义画笔] - final Paint paintBrush = Paint() - //画笔颜色 - ..color = Colors.black - //画笔笔触类型 - ..strokeCap = StrokeCap.round - //是否启动抗锯齿 - ..isAntiAlias = true - //绘画风格,默认为填充 - // ..style = PaintingStyle.fill - //画笔的宽度 - ..style = PaintingStyle.stroke - ..strokeWidth = 0.5.r; - - @override - void paint(Canvas canvas, Size size) { - // canvas.drawPoints(PointMode.points, thePoints, paintBrush); - - var points = ctrl.value; - var _length = points.length; - for (int i = 0; i < _length; i++) { - GestureHandwritingRecording item = points[i]; - GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null; - - Offset offsetData = item.data; - Offset? nextOffsetData = nextItem?.data; - if (nextOffsetData != null && item.stroke == nextItem?.stroke) { - canvas.drawLine(offsetData, nextOffsetData, paintBrush); - } - } - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return false; // 如果 oldDelegate 不是 MyCustomPainter 的实例,则总是重绘 - } -} - class HandWritingDrawingPainter extends CustomPainter { final ValueNotifier> ctrl; HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl); @@ -804,126 +765,126 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L return Container( height: 62.h, - padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + padding: EdgeInsets.symmetric(horizontal: 10.w), alignment: Alignment.center, color: Color.fromRGBO(0, 0, 0, 0.4), - child: Column( - mainAxisSize: MainAxisSize.min, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Container(alignment: Alignment.centerRight, child: StudentManuscriptBtn()), // 查看原稿按钮 - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (usePlaybar.handWritingReady.value) - InkWell( - onTap: () => easyThrottle('job_handwriting_play_pause', () { - if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹'); + if (usePlaybar.handWritingReady.value) + InkWell( + onTap: () => easyThrottle('job_handwriting_play_pause', () { + if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹'); - usePlaybar.playPause.value = !usePlaybar.playPause.value; - usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); - }), - child: Icon( - !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline, - color: Colors.white, - size: 28.r, - ), - ) - else - SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), - SizedBox(width: 6.w), - Expanded( - child: LayoutBuilder(builder: (context, constraints) { - final double containerWidth = constraints.maxWidth; // 展示区域总宽度 - var unitScale = containerWidth / timeConsuming; // 单位刻度 - var pauseIntervalsLength = pauseIntervals.length; - - List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { - bool isLast = e == pauseIntervalsLength - 1; - bool isFirst = e == 0; - var item = pauseIntervals[e]; - return Positioned( - top: 0, - left: unitScale * item.startTime, - child: Container( - width: unitScale * (item.apart ?? 0), - height: 8.h, - decoration: BoxDecoration( - color: Color.fromRGBO(202, 201, 201, 1), - borderRadius: isFirst - ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) - : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), - ), - ), - ); - }).toList(); - - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - children: [ - Container( - height: 8.h, - width: containerWidth, - decoration: BoxDecoration( - // color: Color.fromRGBO(146, 146, 146, 1), - color: Colors.white, - borderRadius: BorderRadius.circular(50.r), - ), - ), - ...pauseTickMarks, - Container( - height: 8.h, - width: containerWidth, - // color: Theme.of(context).primaryColor, - child: SliderTheme( - data: SliderTheme.of(context).copyWith( - trackHeight: 8.h, // 轨道高度 - trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 - activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 - inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), - thumbColor: Colors.white, // 滑块颜色 - overlayShape: RoundSliderOverlayShape(overlayRadius: 0), - overlayColor: Colors.black54, // 滑块外圈颜色 - // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 - ), - child: Slider( - value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), - min: 0.0, - max: usePlaybar.handwritingDuration.value.toDouble(), - inactiveColor: Colors.transparent, - onChangeEnd: (value) { - if (!usePlaybar.handWritingReady.value) return; - usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 - usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - onChanged: (double value) { - if (!usePlaybar.handWritingReady.value) return; - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - ), - ), - ), - ], - ), - SizedBox(height: 4.h), - SizedBox( - width: containerWidth, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), - quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), - ], - ), - ) - ], - ); - }), + usePlaybar.playPause.value = !usePlaybar.playPause.value; + usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); + }), + child: Icon( + !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline, + color: Colors.white, + size: 28.r, ), - SizedBox(width: 16.w), + ) + else + SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), + SizedBox(width: 6.w), + Expanded( + child: LayoutBuilder(builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + var unitScale = containerWidth / timeConsuming; // 单位刻度 + var pauseIntervalsLength = pauseIntervals.length; + + List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = pauseIntervals[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), + height: 10.h, + decoration: BoxDecoration( + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: isFirst + ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) + : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), + ), + ), + ); + }).toList(); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Container( + height: 10.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Colors.white, + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 10.h, + width: containerWidth, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 10.h, // 轨道高度 + trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 8.h), + SizedBox( + width: containerWidth, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), + quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + ], + ), + ) + ], + ); + }), + ), + SizedBox(width: 16.w), + Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ InkWell( onTap: () => easyThrottle('job_handwriting_speed', () { var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value); @@ -944,8 +905,10 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L ), ), ), + SizedBox(height: 7.h), + StudentManuscriptBtn(), ], - ) + ), ], ), ); @@ -957,15 +920,17 @@ class StudentManuscriptBtn extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + var _showVal = ref.watch(jobHandwritingStudentManuscriptProvider); return InkWell( onTap: () => easyThrottle('job_handwriting_udent_manuscript', () { var showManuscript = ref.read(jobHandwritingStudentManuscriptProvider).showManuscript; ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(!showManuscript)); }), child: Container( - padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 1.h), - decoration: BoxDecoration(color: Colors.grey, borderRadius: BorderRadius.circular(4.r)), - child: quickText('学生原稿', color: Colors.white, size: 8.sp), + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: + BoxDecoration(color: _showVal.showManuscript ? Theme.of(context).primaryColor : Colors.grey, borderRadius: BorderRadius.circular(4.r)), + child: quickText('学生原稿', color: Colors.white, size: 8.sp, align: TextAlign.center), ), ); } diff --git a/marking_app/pubspec.yaml b/marking_app/pubspec.yaml index 324ff6a..f457dc2 100644 --- a/marking_app/pubspec.yaml +++ b/marking_app/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.106 +version: 1.0.107+2 environment: sdk: ">=2.17.1 <3.0.0"