Merge branch 'marking_annotations_04_29'

This commit is contained in:
1147192855@qq.com 2024-05-20 15:34:34 +08:00
commit 88dd4c4c16
28 changed files with 1713 additions and 1171 deletions

View File

@ -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 For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials, [online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference. samples, guidance on mobile development, and a full API reference.
fvm flutter build apk --release --no-tree-shake-icons

View File

@ -35,7 +35,14 @@
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- Provider -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application> </application>
<!-- 访问电话状态 --> <!-- 访问电话状态 -->
@ -47,8 +54,10 @@
<!-- 获取当前WiFi接入的状态以及WLAN热点的信息 --> <!-- 获取当前WiFi接入的状态以及WLAN热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取当前设备存储权限 --> <!-- 获取当前设备存储权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACTION_MANAGE_UNKNOWN_APP_SOURCES"/>
<!-- 这个权限用于app安装 --> <!-- 这个权限用于app安装 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- 屏幕常亮权限 --> <!-- 屏幕常亮权限 -->
@ -58,4 +67,6 @@
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/> <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
<!-- Permissions options for the `notification` group --> <!-- Permissions options for the `notification` group -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest> </manifest>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="Android/data/com.example.marking_app/" name="files_root" />
<external-path path="." name="external_storage_root" />
</paths>

View File

@ -13,9 +13,13 @@
<!-- 获取当前WiFi接入的状态以及WLAN热点的信息 --> <!-- 获取当前WiFi接入的状态以及WLAN热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取当前设备存储权限 --> <!-- 获取当前设备存储权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
<!-- <uses-permission android:name="android.permission.INTERNET"/> --> <!-- <uses-permission android:name="android.permission.INTERNET"/> -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 这个权限用于app安装 --> <!-- 这个权限用于app安装 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>

View File

@ -0,0 +1,6 @@
enum ReviewMarksBottomBtnsEnum {
DRAG, //
HANDWRITING, //
RETURN_PREVIOUS_LEVEL, //
CLEAR_ALL //
}

View File

@ -15,8 +15,23 @@ class BottomAnnotationSwitchCleanall extends Object {
BottomAnnotationSwitchCleanall({this.cleanAll = false, this.previousStep = false, this.uploadImage = false}); BottomAnnotationSwitchCleanall({this.cleanAll = false, this.previousStep = false, this.uploadImage = false});
factory BottomAnnotationSwitchCleanall.fromJson(Map<String, dynamic> srcJson) => factory BottomAnnotationSwitchCleanall.fromJson(Map<String, dynamic> srcJson) => _$BottomAnnotationSwitchCleanallFromJson(srcJson);
_$BottomAnnotationSwitchCleanallFromJson(srcJson);
Map<String, dynamic> toJson() => _$BottomAnnotationSwitchCleanallToJson(this); Map<String, dynamic> 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<String, dynamic> srcJson) =>
_$BottomAnnotationSwitchCleanallOfMarkingFromJson(srcJson);
Map<String, dynamic> toJson() => _$BottomAnnotationSwitchCleanallOfMarkingToJson(this);
}

View File

@ -41,3 +41,11 @@ class GestureHandwritingRecording {
required this.intervalTime, required this.intervalTime,
}); });
} }
/**
* 稿
*/
class ShowStudentMmanuscript {
bool showManuscript; // 稿
ShowStudentMmanuscript(this.showManuscript);
}

View File

@ -35,8 +35,17 @@ class TestQuestionsImageInfo extends Object {
double? imageHeightOffsetend; double? imageHeightOffsetend;
TestQuestionsImageInfo( double zoom; //
{required this.width, required this.height, required this.url, required this.boxWidth, required this.boxHeight, this.pixelRatio = 1}) {
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('图片宽度:$width');
// print('图片高度:$height'); // print('图片高度:$height');
@ -46,11 +55,11 @@ class TestQuestionsImageInfo extends Object {
pixelRatio = width / boxWidth; pixelRatio = width / boxWidth;
scale = boxWidth / width; scale = boxWidth / width;
scaleHeight = scale! * height; scaleHeight = scale! * height * zoom;
scaleWidth = scale! * width; scaleWidth = scale! * width * zoom;
if (scaleHeight != null) { if (scaleHeight != null) {
imageHeightOffsetStart = (boxHeight - scaleHeight!) / 2; imageHeightOffsetStart = boxHeight <= scaleHeight! ? 0 : (boxHeight - scaleHeight!) / 2;
imageHeightOffsetend = imageHeightOffsetStart! + scaleHeight!; imageHeightOffsetend = imageHeightOffsetStart! + scaleHeight!;
} }
} }

View File

@ -96,9 +96,9 @@ class MarkingTextQuestion extends Object {
@JsonKey(name: 'papersUrlStr') @JsonKey(name: 'papersUrlStr')
List<String>? papersUrlStr; List<String>? papersUrlStr;
// // //
@JsonKey(name: 'commentImageUrlTodo') // @JsonKey(name: 'commentImageUrlTodo')
List<String>? commentImageUrlTodo; // List<String>? commentImageUrlTodo;
// Map // Map
@JsonKey(name: 'commentImageUrlMap') @JsonKey(name: 'commentImageUrlMap')
@ -115,8 +115,8 @@ class MarkingTextQuestion extends Object {
@JsonKey(name: 'historicalScorings') @JsonKey(name: 'historicalScorings')
List<HistoricalScoring>? historicalScorings; List<HistoricalScoring>? historicalScorings;
MarkingTextQuestion(this.id, this.totalScore, this.isFinish, this.subQuestionDetailList, this.isException, MarkingTextQuestion(
this.questionNum, this.score, this.studentAnswerList, this.id, this.totalScore, this.isFinish, this.subQuestionDetailList, this.isException, this.questionNum, this.score, this.studentAnswerList,
// this.questionIndex, // this.questionIndex,
{required this.commentImageUrl, {required this.commentImageUrl,
required this.lastOne, required this.lastOne,
@ -130,7 +130,7 @@ class MarkingTextQuestion extends Object {
// this.totalCount = 0, // this.totalCount = 0,
// this.currentIndex = 0, // this.currentIndex = 0,
this.papersUrl = const [], this.papersUrl = const [],
this.commentImageUrlTodo, // this.commentImageUrlTodo,
this.commentImageUrlMap = const {}}) { this.commentImageUrlMap = const {}}) {
score = isFinish ? score : null; score = isFinish ? score : null;
completeRating = isFinish && score != null; completeRating = isFinish && score != null;
@ -140,14 +140,20 @@ class MarkingTextQuestion extends Object {
commentImageUrlMap = Map(); commentImageUrlMap = Map();
if (commentImageUrl.isNotEmpty) { if (commentImageUrl.isNotEmpty) {
for (var element in commentImageUrl) { // for (var element in commentImageUrl) {
commentImageUrlMap[element] = '$element?${DateTime.now().millisecondsSinceEpoch}'; // commentImageUrlMap[element] = '$element?${DateTime.now().millisecondsSinceEpoch}';
// }
for (var i = 0; i < commentImageUrl.length; i++) {
var element = commentImageUrl[i];
var originalImage = studentAnswerList[i];
commentImageUrlMap[originalImage] = 'https:$element?${DateTime.now().millisecondsSinceEpoch}';
} }
} else { } else {
for (var element in studentAnswerList) { for (var element in studentAnswerList) {
commentImageUrlMap[element] = element; commentImageUrlMap[element] = element;
} }
} }
// if (historicalScore != null) { // if (historicalScore != null) {
// this.historicalScorings = (jsonDecode(historicalScore!) as List<dynamic>).map((e) { // this.historicalScorings = (jsonDecode(historicalScore!) as List<dynamic>).map((e) {
// return HistoricalScoring.fromJson(e as Map<String, dynamic>); // return HistoricalScoring.fromJson(e as Map<String, dynamic>);
@ -165,10 +171,6 @@ class MarkingTextQuestion extends Object {
factory MarkingTextQuestion.fromJson(Map<String, dynamic> srcJson) => _$MarkingTextQuestionFromJson(srcJson); factory MarkingTextQuestion.fromJson(Map<String, dynamic> srcJson) => _$MarkingTextQuestionFromJson(srcJson);
List<String> getImageData() { List<String> getImageData() {
if (commentImageUrlTodo != null && commentImageUrlTodo!.isNotEmpty) {
return commentImageUrlTodo!;
}
if (commentImageUrl.isNotEmpty) { if (commentImageUrl.isNotEmpty) {
return commentImageUrl; return commentImageUrl;
} }
@ -178,10 +180,8 @@ class MarkingTextQuestion extends Object {
bool setImageList(String resImage, int imageIndex) { bool setImageList(String resImage, int imageIndex) {
try { try {
commentImageUrlTodo ??= getImageData().map((e) => e).toList();
String oldImage = studentAnswerList[imageIndex]; String oldImage = studentAnswerList[imageIndex];
commentImageUrlMap[oldImage] = '$resImage?${DateTime.now().millisecondsSinceEpoch}'; commentImageUrlMap[oldImage] = '$resImage?${DateTime.now().millisecondsSinceEpoch}';
commentImageUrlTodo![imageIndex] = resImage;
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
@ -220,11 +220,7 @@ class SubQuestions extends Object {
bool completeRating; bool completeRating;
SubQuestions( SubQuestions(
{required this.subQuestionScore, {required this.subQuestionScore, required this.subQuestionNum, this.subQuestionGotScore, required this.isFinish, this.completeRating = false}) {
required this.subQuestionNum,
this.subQuestionGotScore,
required this.isFinish,
this.completeRating = false}) {
subQuestionGotScore = isFinish ? subQuestionGotScore : null; subQuestionGotScore = isFinish ? subQuestionGotScore : null;
completeRating = isFinish && subQuestionGotScore != null; completeRating = isFinish && subQuestionGotScore != null;
} }

View File

@ -22,6 +22,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:marking_app/common/mixin/common.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/base_structure_result.dart';
import 'package:marking_app/common/model/common/upload_img_secret_key.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/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/test_questions_image_info.dart';
import 'package:marking_app/common/model/job/upload_file_interface_config.dart'; import 'package:marking_app/common/model/job/upload_file_interface_config.dart';
@ -29,10 +30,12 @@ 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/annotation_graffiti_switch.dart';
import 'package:marking_app/common/model/marking/do_marking_keyboard_model.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_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/common/model/marking/switch_keyboard_to_reload_images.dart';
import 'package:marking_app/pages/common/event_bus_mixin.dart'; 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/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/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_height_provider.dart';
import 'package:marking_app/pages/marking/provider/zoom_history_provider.dart'; import 'package:marking_app/pages/marking/provider/zoom_history_provider.dart';
import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart'; import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart';
@ -46,7 +49,8 @@ import 'dart:ui' as ui;
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:zoom_widget/zoom_widget.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'; part 'PictureOverview.g.dart';
typedef PageChanged = void Function(int index); typedef PageChanged = void Function(int index);
@ -66,6 +70,8 @@ class PictureOverview extends StatefulHookConsumerWidget {
final bool annotationsFlag; final bool annotationsFlag;
final String testQuestionNumber; final String testQuestionNumber;
final Map<String, String> commentImageMap; final Map<String, String> commentImageMap;
final MarkingTextQuestion data;
final Function callAnnotationTips;
const PictureOverview({ const PictureOverview({
required this.imageItems, required this.imageItems,
@ -74,6 +80,8 @@ class PictureOverview extends StatefulHookConsumerWidget {
required this.testQuestionNumber, required this.testQuestionNumber,
required this.questionNum, required this.questionNum,
required this.markingUserId, required this.markingUserId,
required this.data,
required this.callAnnotationTips,
this.homework = false, this.homework = false,
this.imageScale = 1, this.imageScale = 1,
this.imagePosition, this.imagePosition,
@ -84,7 +92,7 @@ class PictureOverview extends StatefulHookConsumerWidget {
PictureOverviewState createState() => PictureOverviewState(); PictureOverviewState createState() => PictureOverviewState();
} }
class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMixin { class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMixin, EventBusMixin {
final GlobalKey theglobalKey = GlobalKey(); final GlobalKey theglobalKey = GlobalKey();
final GlobalKey<_ExamPaperDrawingState> examPaperDrawingKey = GlobalKey<_ExamPaperDrawingState>(); final GlobalKey<_ExamPaperDrawingState> examPaperDrawingKey = GlobalKey<_ExamPaperDrawingState>();
final GlobalKey zoomGlobalKey = GlobalKey(); // zoom final GlobalKey zoomGlobalKey = GlobalKey(); // zoom
@ -100,6 +108,12 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
late RemoveListener _annotationsListener; // late RemoveListener _annotationsListener; //
File? temFile; // File? temFile; //
//
Offset? globalPosition; //
MarkingHistoryZoomInfo? zoomInfo;
bool illegalArea = false; //
final GlobalKey _zoomKey = GlobalKey<State<Zoom>>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -108,11 +122,12 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
bool flag = value.questionNum == widget.questionNum && value.markingUserId == widget.markingUserId; bool flag = value.questionNum == widget.questionNum && value.markingUserId == widget.markingUserId;
if (flag) { if (flag) {
if (value.positionX != 0 && value.positionY != 0) { if (value.positionX != 0 && value.positionY != 0) {
zoomOffset = Offset(value.positionX, value.positionY); // zoomOffset = Offset(value.positionX, value.positionY);
} }
if (value.scale < 1) { if (value.scale < 1) {
initScale = value.scale; 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!));
} }
} }
}); });
@ -123,19 +138,49 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
graffitiSwitch = state; graffitiSwitch = state;
toUpState(setState, () {}, mounted); toUpState(setState, () {}, mounted);
}); });
// 线
eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) async {
widget.callAnnotationTips(); //
if (ref.read(drawMarkingProvider).data.isEmpty) {
if (widget.data.commentImageUrl.isNotEmpty) {
bool? res = await showDialog<bool>(
//
barrierDismissible: false,
context: context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹"), actions: <Widget>[
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 @override
void dispose() { void dispose() {
super.dispose();
_annotationsListener(); _annotationsListener();
eventCancel();
try { try {
_imageStream?.removeListener(_imageStreamListener!); _imageStream?.removeListener(_imageStreamListener!);
if (temFile != null) { if (temFile != null) {
bool flieExist = temFile!.existsSync(); bool flieExist = temFile!.existsSync();
if (flieExist) temFile!.delete(); if (flieExist) temFile!.delete();
} }
// if (zoomOffset != null) saveZoomPosition();
} catch (e) {} } catch (e) {}
super.dispose();
} }
Future<FileResult?> saveImage() async { Future<FileResult?> saveImage() async {
@ -146,9 +191,12 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
// //
RenderRepaintBoundary? boundary = theglobalKey.currentContext!.findRenderObject() as RenderRepaintBoundary?; RenderRepaintBoundary? boundary = theglobalKey.currentContext!.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null; if (boundary == null) return null;
double dpr = MediaQuery.of(context).devicePixelRatio; // double dpr = MediaQuery.of(context).devicePixelRatio;
// double dpr = ui.window.devicePixelRatio;
ui.Image image = await boundary.toImage(pixelRatio: dpr); 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); ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
if (byteData == null) { if (byteData == null) {
/// null /// null
@ -162,11 +210,14 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
temFile = file; 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(); RestClient _client = await getClient();
BaseStructureResult<UploadFileInterfaceConfig> resUploadConfig =
await _client.getUploadFile(UploadFileInterfaceConfigParams( BaseStructureResult<UploadFileInterfaceConfig> resUploadConfig = await _client.getMarkingUploadFile(UploadFileInterfaceConfigParams(
fileName: '1.png', fileName: '1.png',
fileMd5: fileMd5.toString(), fileMd5: fileMd5.toString(),
contentLength: temFile!.lengthSync(), contentLength: temFile!.lengthSync(),
@ -179,8 +230,7 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
if (resUploadConfig.data!.uploadUri == null) { if (resUploadConfig.data!.uploadUri == null) {
return FileResult(myObject: '', success: true, url: resUploadConfig.data!.downloadUri); return FileResult(myObject: '', success: true, url: resUploadConfig.data!.downloadUri);
} }
FileResult? resFile = FileResult? resFile = await ref.read(uploadFileProvider.notifier).getUploadFileConfig(resUploadConfig.data!, temFile!);
await ref.read(uploadFileProvider.notifier).getUploadFileConfig(resUploadConfig.data!, temFile!);
// FileResult? resFile = await ref // FileResult? resFile = await ref
// .read(uploadFileProvider.notifier) // .read(uploadFileProvider.notifier)
// .uploadFile(temFile!.path, widget.imageItems[currentIndex], ref.read(userProvider).id.toString()); // .uploadFile(temFile!.path, widget.imageItems[currentIndex], ref.read(userProvider).id.toString());
@ -210,27 +260,60 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
FastData.getInstance().setMarkingZoomInfo(info); 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 { void onScaleUpdate(double scale, double zoom) async {
print('这是第一个scale$scale'); // print('zoom$zoom');
print('这是第二个noScale$scale1'); // print('scale${scale}');
// MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); // MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo();
MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo();
double positionX = historyZoomInfo?.positionX ?? 0; double positionX = historyZoomInfo?.positionX ?? 0;
double positionY = historyZoomInfo?.positionY ?? 0; double positionY = historyZoomInfo?.positionY ?? 0;
MarkingHistoryZoomInfo info = MarkingHistoryZoomInfo( MarkingHistoryZoomInfo info = MarkingHistoryZoomInfo(
scale: scale1, scale: zoom,
positionX: positionX, positionX: positionX,
positionY: positionY, positionY: positionY,
questionNum: widget.questionNum, questionNum: widget.questionNum,
markingUserId: widget.markingUserId, 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,
width: imagInfoModel!.width,
zoom: zoom,
);
}
FastData.getInstance().setMarkingZoomInfo(info); FastData.getInstance().setMarkingZoomInfo(info);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
DoMarkingKeyboardModel _model = ref.watch(markingKeyboardProvider);
return Container( return Container(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
@ -257,10 +340,9 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
temFile = file; temFile = file;
print('更新需要上传的文件'); print('更新需要上传的文件');
}, },
imageBuilder: (context, imageProvider) { imageBuilder: (imageBuilderContext, imageProvider) {
Image imageWidget = Image(image: imageProvider, fit: BoxFit.fitWidth); Image imageWidget = Image(image: imageProvider, fit: BoxFit.fitWidth);
if (imagInfoModel == null || if (imagInfoModel == null || (imagInfoModel?.boxHeight != containerHeight || imagInfoModel?.boxWidth != containerWidth)) {
(imagInfoModel?.boxHeight != containerHeight || imagInfoModel?.boxWidth != containerWidth)) {
if (_imageStreamListener != null) _imageStream?.removeListener(_imageStreamListener!); if (_imageStreamListener != null) _imageStream?.removeListener(_imageStreamListener!);
_imageStreamListener = ImageStreamListener((ImageInfo info, bool _) { _imageStreamListener = ImageStreamListener((ImageInfo info, bool _) {
imagInfoModel = TestQuestionsImageInfo( imagInfoModel = TestQuestionsImageInfo(
@ -271,7 +353,6 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
height: info.image.height.toDouble(), height: info.image.height.toDouble(),
width: info.image.width.toDouble(), width: info.image.width.toDouble(),
); );
printJson(imagInfoModel!.toJson());
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
ref.read(zoomHeightProvider.notifier).setState(imagInfoModel?.scaleHeight ?? 0.0); ref.read(zoomHeightProvider.notifier).setState(imagInfoModel?.scaleHeight ?? 0.0);
}); });
@ -279,20 +360,111 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
_imageStream = imageWidget.image.resolve(ImageConfiguration())..addListener(_imageStreamListener!); _imageStream = imageWidget.image.resolve(ImageConfiguration())..addListener(_imageStreamListener!);
} }
var btnEnum = ref.watch(doPaperBottomReviewMarksProvider);
// return imageWidget; // return imageWidget;
return Zoom( return Listener(
// initTotalZoomOut: true, behavior: HitTestBehavior.opaque,
child: imageWidget, onPointerMove: (PointerMoveEvent details) {
maxZoomWidth: containerWidth, if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return;
canvasColor: Colors.transparent, if (globalPosition != null) {
backgroundColor: Colors.transparent, //
maxZoomHeight: imagInfoModel?.scaleHeight, double dx = globalPosition!.dx;
initScale: initScale ?? 1, double dy = globalPosition!.dy;
initPosition: zoomOffset,
// initPosition: , double dxNew = details.localPosition.dx;
// onPositionUpdate: onPositionUpdate, double dyNew = details.localPosition.dy;
onScaleUpdate: onScaleUpdate, if ((dxNew - dx).abs() > 22 || (dyNew - dy).abs() > 22) return;
// zoomSensibility: 0.5, }
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;
var _theKey = _zoomKey.currentState;
print(_theKey);
double remainingHeight = imagInfoModel!.imageHeightOffsetStart!; //
if (remainingHeight > 1) {
localPosition = Offset(localPosition.dx, localPosition.dy - remainingHeight);
}
// 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 / _theZoomVal, localPosition.dy / _theZoomVal);
if (zoomOffset != null) {
//
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));
var newVal1 = ref.read(drawMarkingProvider).offsets..add(localPosition);
ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal, newVal1));
widget.callAnnotationTips();
},
// onPointerDown: (PointerDownEvent event) {
// },
onPointerUp: (PointerUpEvent details) {
if (btnEnum != ReviewMarksBottomBtnsEnum.HANDWRITING) return;
//
if (illegalArea) return;
globalPosition = 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));
},
child: IgnorePointer(
ignoring: btnEnum != ReviewMarksBottomBtnsEnum.DRAG,
child: Zoom(
key: _zoomKey,
// 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 != null ? (imagInfoModel!.scaleHeight! / imagInfoModel!.zoom) : null,
initScale: initScale ?? 1,
initPosition: zoomOffset,
onScaleUpdate: onScaleUpdate,
onPositionUpdate: onPanUpPosition,
),
),
); );
}, },
); );
@ -303,24 +475,17 @@ class PictureOverviewState extends ConsumerState<PictureOverview> with CommonMix
// //
class ExamPaperDrawing extends StatefulHookConsumerWidget { class ExamPaperDrawing extends StatefulHookConsumerWidget {
String imgUrl; // String imgUrl;
bool homework; Widget child;
BoxDecoration? decoration; BoxDecoration? decoration;
AnnotationGraffitiSwitch graffitiSwitch; AnnotationGraffitiSwitch graffitiSwitch;
List<GestureRecording>? points;
List<dynamic>? pointsPureData;
ValueNotifier<Map<String, ui.Image>> imageLoaded;
GlobalKey globalKey; GlobalKey globalKey;
// Function(String) imageCall; // Function(String) imageCall;
ExamPaperDrawing({ ExamPaperDrawing({
required this.imgUrl, // required this.imgUrl,
required this.homework, required this.child,
required this.points,
required this.pointsPureData,
required this.graffitiSwitch, required this.graffitiSwitch,
required this.globalKey, required this.globalKey,
required this.imageLoaded,
this.decoration, this.decoration,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -329,73 +494,38 @@ class ExamPaperDrawing extends StatefulHookConsumerWidget {
_ExamPaperDrawingState createState() => _ExamPaperDrawingState(); _ExamPaperDrawingState createState() => _ExamPaperDrawingState();
} }
class _ExamPaperDrawingState extends ConsumerState<ExamPaperDrawing> class _ExamPaperDrawingState extends ConsumerState<ExamPaperDrawing> with EventBusMixin<BottomAnnotationSwitchCleanallOfMarking> {
with EventBusMixin<BottomAnnotationSwitchCleanall> {
late Future<ui.Image?> _future; //
// //
late List<GestureRecording> points; late RemoveListener removeListener;
late List<dynamic> pointsPureData; late ValueNotifier<List<GestureRecording>> _vnHandWritings;
// late List<Offset?> pointsPureData = [];
bool _isEraserPressed = false; //
Offset? _eraserPosition; //
Offset? globalPosition = null; //
Future<ui.Image?> loadImage(String url) async {
try {
Map<String, ui.Image> 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);
// }
// }
@override @override
void initState() { void initState() {
points = widget.points ?? []; _vnHandWritings = ValueNotifier<List<GestureRecording>>([]);
pointsPureData = widget.pointsPureData ?? []; removeListener = ref.read(drawMarkingProvider.notifier).addListener((state) {
print('图片地址:${widget.imgUrl}'); pointsPureData = state.offsets;
_future = loadImage(widget.imgUrl); _vnHandWritings.value = [...state.data];
}, fireImmediately: false);
// 线 // 线
eventOn(callback: (BottomAnnotationSwitchCleanall item) { eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) {
if (item.previousStep) { if (item.previousStep) {
if (points.isEmpty) { if (ref.read(drawMarkingProvider).data.isEmpty) {
ToastUtils.showInfo('批注已清空');
return; return;
} }
var index = pointsPureData.toList().lastIndexOf(null); var index = pointsPureData.toList().lastIndexOf(null);
if (index != -1) { if (index != -1) {
if (index + 1 == pointsPureData.length) { if (index + 1 == pointsPureData.length) {
pointsPureData = pointsPureData.sublist(0, index); pointsPureData = pointsPureData.sublist(0, index);
points.sublist(0, index);
ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index), pointsPureData));
index = pointsPureData.toList().lastIndexOf(null); index = pointsPureData.toList().lastIndexOf(null);
index == -1 ? -1 : index + 1; index == -1 ? -1 : index + 1;
} }
if (index != -1) { if (index != -1) {
pointsPureData = pointsPureData.sublist(0, index); pointsPureData = pointsPureData.sublist(0, index);
points = points.sublist(0, index); ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index), pointsPureData));
toUpState(setState, () {}, mounted);
} else { } else {
item.cleanAll = true; item.cleanAll = true;
} }
@ -406,21 +536,7 @@ class _ExamPaperDrawingState extends ConsumerState<ExamPaperDrawing>
if (item.cleanAll) { if (item.cleanAll) {
pointsPureData.clear(); pointsPureData.clear();
points.clear(); ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], []));
toUpState(setState, () {}, mounted);
}
if (item.uploadImage) {
//
if (pointsPureData.isEmpty) {
ToastUtils.showInfo('请先批注再提交');
return;
}
// _saveImage().then((FileResult? res) {
// if (res != null) {
// widget.imageCall(res.url!);
// }
// });
} }
}); });
super.initState(); super.initState();
@ -428,196 +544,65 @@ class _ExamPaperDrawingState extends ConsumerState<ExamPaperDrawing>
@override @override
void dispose() { void dispose() {
super.dispose();
eventCancel(); eventCancel();
removeListener();
_vnHandWritings.dispose();
super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MyFutureBuilder.buildFutureBuilderOfSingleInstance<ui.Image>( print('_ExamPaperDrawingState的build....');
context,
_future,
(ui.Image? theImage) {
if (theImage == null) return const Center(child: Text('图片加载错误'));
return LayoutBuilder( return RepaintBoundary(
builder: (BuildContext context, BoxConstraints constraints) { key: widget.globalKey,
final double containerWidth = constraints.maxWidth; // child: CustomPaint(
final double containerHeight = constraints.maxHeight; // isComplex: true,
willChange: true,
final double imageWidth = theImage.width.toDouble(); // foregroundPainter: DrawingPainter(ctrl: _vnHandWritings),
final double imageHeight = theImage.height.toDouble(); // child: widget.child,
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),
),
),
);
},
);
},
); );
} }
} }
class DrawingPainter extends CustomPainter { class DrawingPainter extends CustomPainter {
final List<GestureRecording> points; final ValueNotifier<List<GestureRecording>> ctrl;
final bool isErasing; final Paint paintBrush = Paint();
final ui.Image image; DrawingPainter({required this.ctrl}) : super(repaint: ctrl) {
final bool homework; paintBrush
final double containerWidth; ..color = Colors.red
final double containerHeight; ..strokeCap = StrokeCap.round
double destWidth; ..strokeWidth = 1.5.r;
double destHeight; }
final double imageWidth;
final double imageHeight;
// 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()
..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;
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
double offsetX = (size.width - destWidth) / 2; var points = ctrl.value;
double offsetY = (size.height - destHeight) / 2; var pointsLength = points.length;
if (destWidth < (size.width / 2)) { print('数据.....................[[[[[${points.length}]]]]]');
destWidth = size.width / 2; for (int i = 0; i < pointsLength; i++) {
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++) {
GestureRecording item = points[i]; GestureRecording item = points[i];
GestureRecording nextItem = points[i + 1];
Offset? offsetData = item.data; Offset? offsetData = item.data;
Offset? nextOffsetData = nextItem.data; Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1].data;
if (offsetData != null && nextOffsetData != null) { 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<GestureRecording> thePoints = oldDelegate.points;
// // var flag = oldDelegate.points != points || oldDelegate.isErasing != isErasing;
// return thePoints != points;
// }
@override @override
bool shouldRepaint(DrawingPainter oldDelegate) => true; 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;
}
} }
/** /**
@ -676,51 +661,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 { class CacheNetImageView extends ConsumerWidget {
@ -802,9 +742,7 @@ Widget $localAndNetworkSwitch(
useValueChanged<bool, String>(drawFlag, (oldValue, oldResult) { useValueChanged<bool, String>(drawFlag, (oldValue, oldResult) {
if (!drawFlag) { if (!drawFlag) {
// //
_useSwitch _useSwitch.createTempFile(context, theglobalKey: theglobalKey, examGlobalKey: examGlobalKey).then((File? theFile) {
.createTempFile(context, theglobalKey: theglobalKey, examGlobalKey: examGlobalKey)
.then((File? theFile) {
if (theFile == null) { if (theFile == null) {
// TODO // TODO
// _useSwich.showZoomImg.value true还是展示的原来的绘图组件ExamPaperDrawing // _useSwich.showZoomImg.value true还是展示的原来的绘图组件ExamPaperDrawing
@ -832,50 +770,13 @@ Widget $localAndNetworkSwitch(
}, []); }, []);
print('是否更新视图.... ${_useZoomHistory.initPosition.value}'); print('是否更新视图.... ${_useZoomHistory.initPosition.value}');
return _useSwitch.showZoomImg.value return $MyCachedNetworkImage(
? imageUrl: imageUrl,
/** tempFile: _useSwitch.temFile.value,
Scrollbar( width: containerWidth,
// thumbVisibility: true, height: containerHeight,
thumbVisibility: true, imageBuilder: imageBuilder,
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),
);
} }
class UseLocalAndNetworkSwitch { class UseLocalAndNetworkSwitch {
@ -938,7 +839,7 @@ class UseLocalAndNetworkSwitch {
temFile.value?.delete(); temFile.value?.delete();
temFile.value = file; // temFile.value = file; //
points.value = examGlobalKey.currentState?.points; points.value = examGlobalKey.currentState?._vnHandWritings.value;
pointsPureData.value = examGlobalKey.currentState?.pointsPureData; pointsPureData.value = examGlobalKey.currentState?.pointsPureData;
toPrint(val: '图片保存成功:'); toPrint(val: '图片保存成功:');
return temFile.value; return temFile.value;

View File

@ -29,9 +29,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
final bool isHomeworkCorrection; final bool isHomeworkCorrection;
final VoidCallback? call; final VoidCallback? call;
final MarkingListType? markingtype; final MarkingListType? markingtype;
const TestPaperItem( const TestPaperItem({required this.markingItem, this.markingtype, this.isHomeworkCorrection = false, this.call, Key? key}) : super(key: key);
{required this.markingItem, this.markingtype, this.isHomeworkCorrection = false, this.call, Key? key})
: super(key: key);
@override @override
Widget build(BuildContext context, WidgetRef ref) { 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), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: 120.h, minHeight: 120.h,
maxHeight: 130.h, maxHeight: 144.h,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -117,8 +115,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
margin: EdgeInsets.only(right: 8.w), margin: EdgeInsets.only(right: 8.w),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
color: const Color.fromRGBO(245, 108, 108, 0.236), color: const Color.fromRGBO(245, 108, 108, 0.236),
), ),
child: Text( child: Text(
@ -137,8 +134,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
margin: EdgeInsets.only(right: 8.w), margin: EdgeInsets.only(right: 8.w),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
color: const Color.fromRGBO(4, 201, 208, 0.10), color: const Color.fromRGBO(4, 201, 208, 0.10),
), ),
child: Text( child: Text(
@ -157,8 +153,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
margin: EdgeInsets.only(right: 8.w), margin: EdgeInsets.only(right: 8.w),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius: BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
BorderRadius.only(topLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)),
color: const Color.fromRGBO(231, 236, 255, 1), color: const Color.fromRGBO(231, 236, 255, 1),
), ),
child: Text( child: Text(
@ -270,10 +265,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
Text( Text(
'${markingItem.finishCount}', '${markingItem.finishCount}',
style: TextStyle( style: TextStyle(
color: markingItem.isFinish && isHomeworkCorrection color: markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor, fontSize: 12.sp),
? Colors.green
: Theme.of(context).primaryColor,
fontSize: 12.sp),
), ),
Text( Text(
'/', '/',
@ -299,8 +291,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
style: TextStyle(color: Colors.white, fontSize: 8.sp), style: TextStyle(color: Colors.white, fontSize: 8.sp),
), ),
// linearStrokeCap: LinearStrokeCap.butt, // linearStrokeCap: LinearStrokeCap.butt,
progressColor: progressColor: markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor,
markingItem.isFinish && isHomeworkCorrection ? Colors.green : Theme.of(context).primaryColor,
backgroundColor: const Color.fromRGBO(219, 224, 243, 1), backgroundColor: const Color.fromRGBO(219, 224, 243, 1),
barRadius: Radius.circular(10.r), barRadius: Radius.circular(10.r),
), ),
@ -503,9 +494,7 @@ class TestPaperItem extends ConsumerWidget with CommonMixin {
RestClient client = await getClient(); RestClient client = await getClient();
BaseStructureResult<bool?> result = await client.endMarkingTask(markingUserId); BaseStructureResult<bool?> result = await client.endMarkingTask(markingUserId);
if (result.code == RequestConfig.successCode && result.data == null ? false : result.data!) { if (result.code == RequestConfig.successCode && result.data == null ? false : result.data!) {
ref ref.read(currentTaskIdProvider.notifier).setDoTaskEntity(CurrentReviewTask(taskId: markingItem.markingUserId, refresh: true));
.read(currentTaskIdProvider.notifier)
.setDoTaskEntity(CurrentReviewTask(taskId: markingItem.markingUserId, refresh: true));
} else { } else {
ToastUtils.getFluttertoast(context: context, msg: '提交失败'); ToastUtils.getFluttertoast(context: context, msg: '提交失败');
} }

View File

@ -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<BottomAnnotationSwitch>
with SingleTickerProviderStateMixin, EventBusMixin<BottomAnnotationSwitchCleanall> {
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);
}
}

View File

@ -224,7 +224,7 @@ class TrajectoryViewState extends ConsumerState<TrajectoryView> {
var zhixinCall = () async { var zhixinCall = () async {
if (mounted) { if (mounted) {
print('执行添加笔画${i},${j}'); // print('执行添加笔画${i},${j}');
trajectorys = List.from(trajectorys)..add(theRecording); trajectorys = List.from(trajectorys)..add(theRecording);
ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys); ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys);
} }

View File

@ -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<JobHome> createState() => _JobHomeState();
// }
// class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin {
// @override
// bool get wantKeepAlive => true;
// late LinkHeaderNotifier _linkNotifier;
// late ValueNotifier<bool> _secondFloorOpen;
// @override
// void initState() {
// getData();
// eventOn(callback: (JobHomeRefreshBus item) => getData());
// _linkNotifier = LinkHeaderNotifier();
// _secondFloorOpen = ValueNotifier<bool>(false);
// super.initState();
// }
// @override
// void dispose() {
// eventCancel();
// _linkNotifier.dispose();
// _secondFloorOpen.dispose();
// super.dispose();
// }
// Future<int> 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: <Widget>[
// 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<EntranceModel> 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<EntranceModel> items;
// SlidingData(this.items);
// @override
// Widget build(BuildContext context) {
// var dataNumber = useState<QuantityToBeReviewedData?>(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<bool> secondFloorOpen;
// final Function refreshCall;
// const SecondFloorWidget(this.linkNotifier, this.secondFloorOpen, {required this.refreshCall, Key? key}) : super(key: key);
// @override
// State<StatefulWidget> createState() => SecondFloorWidgetState();
// }
// class SecondFloorWidgetState extends State<SecondFloorWidget> {
// //
// 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: <Widget>[
// 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/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:marking_app/common/mixin/common.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/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/common/model/marking/marking_list_params.dart';
import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/pages/common/event_bus_mixin.dart';
import 'package:marking_app/routes/RouterManager.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/index.dart';
import 'package:marking_app/utils/my_text.dart'; import 'package:marking_app/utils/my_text.dart';
import 'package:badges/badges.dart' as badges; 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'; part 'job_home.g.dart';
@ -24,44 +573,58 @@ class JobHome extends StatefulWidget {
State<JobHome> createState() => _JobHomeState(); State<JobHome> createState() => _JobHomeState();
} }
class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin { class _JobHomeState extends State<JobHome>
with CommonMixin, EventBusMixin, RefreshDataHandle<JobTaskItem, MarkingListParams>, AutomaticKeepAliveClientMixin {
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
var param = MarkingListParams(isFinish: false, page: 1, limit: 1, pageType: 0);
int totalJobNumber = 0;
List<JobTaskItem> jobDatas = [];
late final EasyRefreshController _refreshController;
@override @override
void initState() { void initState() {
getData(); _refreshController = EasyRefreshController();
eventOn(callback: (JobHomeRefreshBus item) => getData());
super.initState(); super.initState();
} }
@override @override
void dispose() { void dispose() {
_refreshController.dispose();
eventCancel(); eventCancel();
super.dispose(); super.dispose();
} }
Future<int> getData() async { /* 发起请求 => 作业 */
try { Future<void> toGetPageData({bool isReFresh = false}) async {
var _client = await getClient(); if (!isReFresh) {
var _result = await _client.getJobsByPage(MarkingListParams( param.page++;
isFinish: false, }
page: 1, RestClient client = await getClient();
limit: 1, BasePageData<JobTaskItem>? results = await toRefreshData(
pageType: 0, _refreshController,
)); api: client.getJobsByPage,
var data = _result.data?.total ?? 0; params: param,
eventFire(model: QuantityToBeReviewedData(data)); isReFresh: isReFresh,
return data; context: context,
} catch (e) { );
return 0; 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(() {});
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19);
return AnnotatedRegion( return AnnotatedRegion(
value: const SystemUiOverlayStyle( value: const SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000), systemNavigationBarColor: Color(0xFF000000),
@ -71,46 +634,46 @@ class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, Auto
statusBarIconBrightness: Brightness.dark, statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light, statusBarBrightness: Brightness.light,
), ),
child: RefreshIndicator( child: EasyRefresh(
onRefresh: () async => eventFire(model: JobHomeRefreshBus()), firstRefresh: true,
taskIndependence: true,
enableControlFinishLoad: true,
enableControlFinishRefresh: true,
emptyWidget: jobDatas.isEmpty ? $TheJobMainBox(emptyWidget: MyEmptyWidget()) : null,
controller: _refreshController,
header: MaterialHeader(),
footer: TaurusFooter(),
child: ListView( child: ListView(
children: [ children: [
Container( // Container(
constraints: BoxConstraints( // constraints: BoxConstraints(
minHeight: 200.h, // minHeight: 200.h,
maxWidth: double.infinity, // maxWidth: double.infinity,
), // ),
// decoration: BoxDecoration( // // decoration: BoxDecoration(
// image: DecorationImage( // // image: DecorationImage(
// image: AssetImage('assets/images/job_home_top_bgm.png'), // // image: AssetImage('assets/images/job_home_top_bgm.png'),
// fit: BoxFit.fitWidth, // // // fit: BoxFit.fitWidth, //
// ), // // ),
// ), // // ),
child: Image.asset('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), $TheJobMainBox(),
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, // spaceWidth,
// $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0),
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),
), ),
); );
} }
@ -263,3 +826,36 @@ class SlidingData extends HookWidget with EventBusMixin {
return $TermRow(items, dataNumber.value?.num ?? 0); 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,
],
);
}

View File

@ -16,3 +16,15 @@ class JobHandwritingDrawingTrajectoryProviderHandle extends StateNotifier<List<G
state = val; state = val;
} }
} }
// 稿
final jobHandwritingStudentManuscriptProvider = StateNotifierProvider<JobHandwritingStudentManuscriptHandle, ShowStudentMmanuscript>(
(ref) => JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript(true)));
class JobHandwritingStudentManuscriptHandle extends StateNotifier<ShowStudentMmanuscript> {
JobHandwritingStudentManuscriptHandle(ShowStudentMmanuscript progress) : super(progress);
setVal(ShowStudentMmanuscript val) {
state = val;
}
}

View File

@ -375,19 +375,34 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
late ImageStreamListener theImageStreamListener; late ImageStreamListener theImageStreamListener;
late ValueNotifier<List<GestureHandwritingRecording>> _vnHandWritings; late ValueNotifier<List<GestureHandwritingRecording>> _vnHandWritings;
late ValueNotifier<List<GestureHandwritingRecording>> _vnPrimaryHandWritings;
late RemoveListener _jobHandwritingDrawingTrajectoryListener; // late RemoveListener _jobHandwritingDrawingTrajectoryListener; //
late RemoveListener _jobHandwritingDrawingTrajectoryListener1; // 稿
List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = []; List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
List<GestureHandwritingRecording> _packagedHandwritingDataAll = []; List<GestureHandwritingRecording> _packagedHandwritingDataAll = []; //
List<GestureHandwritingRecording> pendingData = []; // List<GestureHandwritingRecording> pendingData = []; //
List<Timer> timers = []; List<Timer> timers = [];
int handwritingTime = 0; int handwritingTime = 0;
int handwritingDuration = 0; int handwritingDuration = 0;
double speed = 1; // double speed = 2.0; //
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]); _vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>(_packagedHandwritingDataAll);
_jobHandwritingDrawingTrajectoryListener1 = ref.read(jobHandwritingStudentManuscriptProvider.notifier).addListener((state) {
// 稿
if (state.showManuscript) {
// 稿
eventFire(model: JobHandwritingPlaybarBus(false)); //
_vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll];
} else {
// 稿
_vnPrimaryHandWritings.value = [];
}
}, fireImmediately: false);
_jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) { _jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) {
_vnHandWritings.value = state; _vnHandWritings.value = state;
}, fireImmediately: false); }, fireImmediately: false);
@ -447,7 +462,9 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
if (e.isActive) e.cancel(); if (e.isActive) e.cancel();
}); });
_jobHandwritingDrawingTrajectoryListener(); _jobHandwritingDrawingTrajectoryListener();
_jobHandwritingDrawingTrajectoryListener1();
_vnHandWritings.dispose(); _vnHandWritings.dispose();
_vnPrimaryHandWritings.dispose();
try { try {
imageStream?.removeListener(theImageStreamListener); imageStream?.removeListener(theImageStreamListener);
eventCancel(); eventCancel();
@ -537,7 +554,7 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
pendingData.addAll(_packagedHandwritingDataAll); pendingData.addAll(_packagedHandwritingDataAll);
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
} }
ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(false));
executableData.forEach((e) { executableData.forEach((e) {
var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e)); var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e));
timers.add(ter); timers.add(ter);
@ -572,6 +589,9 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
_packagedHandwritingDatas.add(newTrajectoryData); // _packagedHandwritingDatas.add(newTrajectoryData); //
_packagedHandwritingDataAll.addAll(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())); // Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); //
} }
@ -579,14 +599,12 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var showManuscript = ref.watch(jobHandwritingStudentManuscriptProvider).showManuscript;
return Container( return Container(
alignment: Alignment.center, alignment: Alignment.center,
child: RepaintBoundary( child: RepaintBoundary(
child: CustomPaint( child: CustomPaint(
willChange: true, foregroundPainter: HandWritingDrawingPainter(ctrl: showManuscript ? _vnPrimaryHandWritings : _vnHandWritings),
isComplex: true,
foregroundPainter: HandWritingDrawingPainter(ctrl: _vnHandWritings),
// size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight),
child: RepaintBoundary( child: RepaintBoundary(
child: $TheCachedNetworkImage( child: $TheCachedNetworkImage(
imageUrl: widget.image, imageUrl: widget.image,
@ -746,8 +764,8 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
}, []); }, []);
return Container( return Container(
height: 60.h, height: 62.h,
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), padding: EdgeInsets.symmetric(horizontal: 10.w),
alignment: Alignment.center, alignment: Alignment.center,
color: Color.fromRGBO(0, 0, 0, 0.4), color: Color.fromRGBO(0, 0, 0, 0.4),
child: Row( child: Row(
@ -785,7 +803,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
left: unitScale * item.startTime, left: unitScale * item.startTime,
child: Container( child: Container(
width: unitScale * (item.apart ?? 0), width: unitScale * (item.apart ?? 0),
height: 8.h, height: 10.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromRGBO(202, 201, 201, 1), color: Color.fromRGBO(202, 201, 201, 1),
borderRadius: isFirst borderRadius: isFirst
@ -802,7 +820,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
Stack( Stack(
children: [ children: [
Container( Container(
height: 8.h, height: 10.h,
width: containerWidth, width: containerWidth,
decoration: BoxDecoration( decoration: BoxDecoration(
// color: Color.fromRGBO(146, 146, 146, 1), // color: Color.fromRGBO(146, 146, 146, 1),
@ -812,12 +830,12 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
), ),
...pauseTickMarks, ...pauseTickMarks,
Container( Container(
height: 8.h, height: 10.h,
width: containerWidth, width: containerWidth,
// color: Theme.of(context).primaryColor, // color: Theme.of(context).primaryColor,
child: SliderTheme( child: SliderTheme(
data: SliderTheme.of(context).copyWith( data: SliderTheme.of(context).copyWith(
trackHeight: 8.h, // trackHeight: 10.h, //
trackShape: RoundedRectSliderTrackShape(), // trackShape: RoundedRectSliderTrackShape(), //
activeTrackColor: Theme.of(context).primaryColor, // activeTrackColor: Theme.of(context).primaryColor, //
inactiveTrackColor: Colors.transparent, // inactiveTrackColor: Colors.transparent, //
@ -847,7 +865,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
), ),
], ],
), ),
SizedBox(height: 4.h), SizedBox(height: 8.h),
SizedBox( SizedBox(
width: containerWidth, width: containerWidth,
child: Row( child: Row(
@ -863,31 +881,61 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
}), }),
), ),
SizedBox(width: 16.w), SizedBox(width: 16.w),
InkWell( Column(
onTap: () => easyThrottle('job_handwriting_speed', () { mainAxisSize: MainAxisSize.min,
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value); mainAxisAlignment: MainAxisAlignment.center,
if (theIndex == PlaybackSpeed.values.length - 1) { children: [
theIndex = -1; InkWell(
} onTap: () => easyThrottle('job_handwriting_speed', () {
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1]; var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
}, duration: Duration(milliseconds: 500)), if (theIndex == PlaybackSpeed.values.length - 1) {
child: Container( theIndex = -1;
// alignment: Alignment., }
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), }, duration: Duration(milliseconds: 500)),
child: quickText( child: Container(
'${usePlaybar.constantFastSpeed.value.name}', // alignment: Alignment.,
color: Color.fromRGBO(79, 114, 244, 1), padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
size: 8.sp, decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
align: TextAlign.center, child: quickText(
'${usePlaybar.constantFastSpeed.value.name}',
color: Color.fromRGBO(79, 114, 244, 1),
size: 8.sp,
align: TextAlign.center,
),
),
), ),
), SizedBox(height: 7.h),
StudentManuscriptBtn(),
],
), ),
], ],
), ),
); );
} }
// 稿
class StudentManuscriptBtn extends ConsumerWidget {
const StudentManuscriptBtn({super.key});
@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: 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),
),
);
}
}
class SysjTime extends StatefulWidget { class SysjTime extends StatefulWidget {
const SysjTime({super.key}); const SysjTime({super.key});
@ -921,7 +969,7 @@ class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRu
class UseBottomPlaybar with EventBusMixin { class UseBottomPlaybar with EventBusMixin {
final ValueNotifier<int> handwritingDuration; // final ValueNotifier<int> handwritingDuration; //
final ValueNotifier<bool> playPause; // final ValueNotifier<bool> playPause; //
final ValueNotifier<PlaybackSpeed> constantFastSpeed; // final ValueNotifier<PlaybackSpeed> constantFastSpeed; //
final ValueNotifier<bool> handWritingReady; final ValueNotifier<bool> handWritingReady;
final ValueNotifier<int> useTime; // final ValueNotifier<int> useTime; //
@ -942,7 +990,7 @@ class UseBottomPlaybar with EventBusMixin {
if ((milliseconds % 1000) > 500) handwritingDuration += 1; if ((milliseconds % 1000) > 500) handwritingDuration += 1;
return UseBottomPlaybar._( return UseBottomPlaybar._(
playPause: useState(false), playPause: useState(false),
constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED), constantFastSpeed: useState(PlaybackSpeed.DOUBLE_SPEED), //
useTime: useState(handwritingDuration), useTime: useState(handwritingDuration),
timer: useState(null), timer: useState(null),
handwritingDuration: useState(handwritingDuration), handwritingDuration: useState(handwritingDuration),

View File

@ -12,6 +12,7 @@ import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio/adapter.dart'; import 'package:dio/adapter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
@ -44,10 +45,8 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
// //
setHttpsPEM() async { setHttpsPEM() async {
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
(client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) {
return true; return true;
}; };
}; };
@ -75,7 +74,7 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
@override @override
void initState() { void initState() {
Future.delayed(Duration(seconds: 2), () => sysProtocol(context)); Future.delayed(Duration(seconds: 1), () => sysProtocol(context));
Future(() { Future(() {
// Provider // Provider
ref.read(userTokenProvider.notifier).clean(); // ref.read(userTokenProvider.notifier).clean(); //
@ -89,14 +88,12 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
receiveTimeout: 8000, receiveTimeout: 8000,
), ),
); );
dio.interceptors dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //
.add(LogInterceptor(responseBody: true, requestBody: true)); //
setHttpsPEM(); setHttpsPEM();
client = RestClient(dio, baseUrl: RequestConfig().loginBaseUrl); client = RestClient(dio, baseUrl: RequestConfig().loginBaseUrl);
_userNameController = TextEditingController() _userNameController = TextEditingController()..addListener(userNameListener);
..addListener(userNameListener);
_passwordController = TextEditingController(); _passwordController = TextEditingController();
_pwdFocus = FocusNode(); _pwdFocus = FocusNode();
_theFocus = FocusNode(); _theFocus = FocusNode();
@ -114,11 +111,10 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
void getShowRegister() async { void getShowRegister() async {
RestClient client = await getClientLogin(); RestClient client = await getClientLogin();
BaseStructureResult<dynamic> resultData = await client.showRegister(); BaseStructureResult<dynamic> resultData = await client.showRegister();
if(resultData.success){ if (resultData.success) {
setState(() { setState(() {
showRegister = resultData.data; showRegister = resultData.data;
}); });
} }
} }
@ -126,8 +122,7 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
String userName = _userNameController.text; String userName = _userNameController.text;
int useNameLength = userName.length; int useNameLength = userName.length;
bool hasNameValNew = useNameLength > 0; bool hasNameValNew = useNameLength > 0;
if (hasNameValNew != hasNameVal) if (hasNameValNew != hasNameVal) toUpState(setState, () => hasNameVal = hasNameValNew, mounted);
toUpState(setState, () => hasNameVal = hasNameValNew, mounted);
const isProd = bool.fromEnvironment('dart.vm.product'); const isProd = bool.fromEnvironment('dart.vm.product');
if (!isProd && useNameLength == 11) { if (!isProd && useNameLength == 11) {
_passwordController.text = userName.substring(useNameLength - 6); _passwordController.text = userName.substring(useNameLength - 6);
@ -182,15 +177,12 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
child: SizedBox( child: SizedBox(
height: 86.w, height: 86.w,
width: 86.w, width: 86.w,
child: Image.asset('assets/images/logo.png', child: Image.asset('assets/images/logo.png', fit: BoxFit.cover),
fit: BoxFit.cover),
), ),
), ),
Container( Container(
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h),
horizontal: 32.w, vertical: 24.h), padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w),
padding: EdgeInsets.only(
top: 34.h, bottom: 16.h, left: 22.w, right: 22.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
border: Border.all(width: 1.w, color: Colors.white), border: Border.all(width: 1.w, color: Colors.white),
@ -219,18 +211,13 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
), ),
decoration: InputDecoration( decoration: InputDecoration(
hintText: "请输入账号", hintText: "请输入账号",
hintStyle: TextStyle( hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)),
fontSize: 16.sp,
color: const Color.fromRGBO(153, 153, 153, 1)),
labelText: "账号", labelText: "账号",
labelStyle: TextStyle( labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
fontSize: 16.sp,
color: const Color.fromRGBO(148, 163, 182, 1)),
suffixIcon: !hasNameVal suffixIcon: !hasNameVal
? null ? null
: Transform.translate( : Transform.translate(
offset: offset: Offset(10, 10), // padding值来设置偏移量
Offset(10, 10), // padding值来设置偏移量
child: IconButton( child: IconButton(
alignment: Alignment.center, alignment: Alignment.center,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -266,19 +253,13 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
onTap: _showPassword, onTap: _showPassword,
child: Icon( child: Icon(
Icons.remove_red_eye, Icons.remove_red_eye,
color: !_isShowPwd color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey,
? Theme.of(context).primaryColor
: Colors.grey,
), ),
), ),
hintStyle: TextStyle( hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)),
fontSize: 16.sp,
color: const Color.fromRGBO(153, 153, 153, 1)),
labelText: "密码", labelText: "密码",
isDense: true, isDense: true,
labelStyle: TextStyle( labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
fontSize: 16.sp,
color: const Color.fromRGBO(148, 163, 182, 1)),
), ),
), ),
SizedBox( SizedBox(
@ -294,10 +275,8 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
checkColor: Colors.white, checkColor: Colors.white,
value: keepPwd, value: keepPwd,
onChanged: (value) { onChanged: (value) {
FocusScope.of(context) FocusScope.of(context).requestFocus(_pwdFocus);
.requestFocus(_pwdFocus); FocusScope.of(context).requestFocus(_theFocus);
FocusScope.of(context)
.requestFocus(_theFocus);
setState(() { setState(() {
keepPwd = value ?? false; keepPwd = value ?? false;
}); });
@ -322,26 +301,20 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
if (showRegister == true) if (showRegister == true)
InkWell( InkWell(
onTap: () { onTap: () {
RouterManager.router.navigateTo( RouterManager.router.navigateTo(context, RouterManager.registerPath);
context, RouterManager.registerPath);
}, },
child: Text( child: Text(
'注册', '注册',
style: TextStyle( style: TextStyle(fontSize: 14.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
fontSize: 14.sp,
color: const Color.fromRGBO(
148, 163, 182, 1)),
)), )),
], ],
), ),
InkWell( InkWell(
onTap: toLogin, onTap: () => easyThrottle('TO_GO_LOGOIN', toLogin),
child: Container( child: Container(
margin: EdgeInsets.symmetric(vertical: 10.h), margin: EdgeInsets.symmetric(vertical: 10.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: canLogin color: canLogin ? const Color.fromRGBO(9, 105, 246, 1) : Colors.grey,
? const Color.fromRGBO(9, 105, 246, 1)
: Colors.grey,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.5), color: const Color.fromRGBO(46, 91, 255, 0.5),
@ -359,8 +332,7 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
height: 50.h, height: 50.h,
child: Text( child: Text(
'登 录', '登 录',
style: TextStyle( style: TextStyle(fontSize: 16.sp, color: Colors.white),
fontSize: 16.sp, color: Colors.white),
), ),
), ),
), ),
@ -374,10 +346,8 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
checkColor: Colors.white, checkColor: Colors.white,
value: readAgreement, value: readAgreement,
onChanged: (value) { onChanged: (value) {
FocusScope.of(context) FocusScope.of(context).requestFocus(_pwdFocus);
.requestFocus(_pwdFocus); FocusScope.of(context).requestFocus(_theFocus);
FocusScope.of(context)
.requestFocus(_theFocus);
setState(() { setState(() {
readAgreement = value ?? false; readAgreement = value ?? false;
}); });
@ -446,34 +416,64 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
setState(() => canLogin = true); 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 { try {
BaseStructureResult<dynamic> resultData = FocusScope.of(context).requestFocus(_theFocus);
await client.toLogin(UserLoginParams(userName, userPwdMd5)); if (!readAgreement) {
UserLogin? userData = resultData.code == 200 && resultData.data != null var resFlag = await showDialog<bool>(
? UserLogin.fromJson(resultData.data) context: context,
: null; barrierDismissible: false,
if (resultData.code != 200 || builder: (BuildContext context) {
userData?.accessToken == null || return CupertinoAlertDialog(
userData?.accessToken == '') { 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>[
TextSpan(text: '《用户协议》《隐式协议》', style: TextStyle(color: Colors.deepOrangeAccent, fontSize: 13.sp)),
],
),
),
),
actions: <Widget>[
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<dynamic> 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 ?? '登录失败,请重试'); return toMsg(resultData.message ?? '登录失败,请重试');
} }
FastData fastData = FastData.getInstance(); FastData fastData = FastData.getInstance();
fastData.setToken(userData!.accessToken); fastData.setToken(userData!.accessToken);
BaseStructureResult<UserInfo> userRes = BaseStructureResult<UserInfo> userRes = await client.getUserInfo('Bearer ${userData.accessToken}');
await client.getUserInfo('Bearer ${userData.accessToken}');
if (userRes.code != 200 || userRes.data == null) { if (userRes.code != 200 || userRes.data == null) {
throw Exception('登录失败,请重试'); throw Exception('登录失败,请重试');
@ -489,8 +489,7 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
ref.read(userTokenProvider.notifier).initToken(); ref.read(userTokenProvider.notifier).initToken();
// //
RouterManager.router.navigateTo(context, RouterManager.root, RouterManager.router.navigateTo(context, RouterManager.root, clearStack: true, transition: getTransition());
clearStack: true, transition: getTransition());
}); });
} catch (e) { } catch (e) {
toPrint(val: e.toString()); toPrint(val: e.toString());
@ -522,6 +521,7 @@ class _TheLoginState extends ConsumerState<TheLogin> with CommonMixin {
return toMsg(msg ?? '登录失败,请重试'); return toMsg(msg ?? '登录失败,请重试');
} finally { } finally {
EasyLoading.dismiss(); EasyLoading.dismiss();
setState(() => canLogin = true);
} }
} }
} }

View File

@ -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/pages/reports/index.dart';
import 'package:marking_app/provider/do_marking_provider.dart'; import 'package:marking_app/provider/do_marking_provider.dart';
import 'package:marking_app/provider/upload_file_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/UpdateDialog.dart';
import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart';
import 'package:marking_app/common/model/sys/system_version.dart'; import 'package:marking_app/common/model/sys/system_version.dart';
@ -28,6 +29,7 @@ import 'package:marking_app/provider/user_provider.dart';
import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/index.dart';
import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/utils/request/rest_client.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:url_launcher/url_launcher.dart';
import 'homework_correction/job_home.dart'; import 'homework_correction/job_home.dart';
@ -72,10 +74,11 @@ class TheMainPageState extends ConsumerState<TheMainPage> with CommonMixin {
// APP升级校验在登录后 // APP升级校验在登录后
_userListener = ref.read(userProvider.notifier).addListener((state) { _userListener = ref.read(userProvider.notifier).addListener((state) {
if (state.id != '0' && state.id != '') { if (state.id != '0' && state.id != '') {
if (!showUpgrade) { if (!showUpgrade) getAppUpgrade(state);
getAppUpgrade(state); _timer?.cancel();
}
_timer = Timer.periodic(Duration(seconds: 40), (e) { _timer = Timer.periodic(Duration(seconds: 40), (e) {
String? routeName = ModalRoute.of(context)?.settings.name;
if (routeName == RouterManager.loginPath) return; // APP
if (!showUpgrade) getAppUpgrade(state); if (!showUpgrade) getAppUpgrade(state);
}); });
} }
@ -104,6 +107,7 @@ class TheMainPageState extends ConsumerState<TheMainPage> with CommonMixin {
} }
void getAppUpgrade(UserInfo user) async { void getAppUpgrade(UserInfo user) async {
if (!bool.fromEnvironment('dart.vm.product')) return;
try { try {
showUpgrade = true; showUpgrade = true;
if (['18888888888'].contains(user.loginName)) return; if (['18888888888'].contains(user.loginName)) return;

View File

@ -0,0 +1,124 @@
import 'package:flutter/cupertino.dart';
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 'package:marking_app/utils/my_text.dart';
import '../provider/do_paper_bottom_review_marks_provider.dart';
//
class DoPaperBottomReviewMarks extends StatefulHookConsumerWidget {
const DoPaperBottomReviewMarks({super.key});
@override
ConsumerState<DoPaperBottomReviewMarks> createState() => _DoPaperBottomReviewMarksState();
}
class _DoPaperBottomReviewMarksState extends ConsumerState<DoPaperBottomReviewMarks> with EventBusMixin<BottomAnnotationSwitchCleanallOfMarking> {
@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),
() async {
var resFlag = await showDialog<bool>(
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: <Widget>[
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),
),
],
),
),
),
);
}
}

View File

@ -14,6 +14,7 @@ import 'package:achievement_view/achievement_view.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:dotted_border/dotted_border.dart'; import 'package:dotted_border/dotted_border.dart';
import 'package:dropdown_search/dropdown_search.dart'; import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
@ -28,6 +29,8 @@ 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/common/upload_img_secret_key.dart';
import 'package:marking_app/common/model/enum/KeyboardType.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/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/current_review_task.dart';
import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart'; import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart';
import 'package:marking_app/common/model/marking/keyboard_assist_event.dart'; import 'package:marking_app/common/model/marking/keyboard_assist_event.dart';
@ -52,6 +55,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/components/marking/selectable_keyboard_bottom.dart';
import 'package:marking_app/pages/common/event_bus_mixin.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/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/pages/marking/provider/rating_progress_provider.dart';
import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart'; import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart';
import 'package:marking_app/provider/do_marking_provider.dart'; import 'package:marking_app/provider/do_marking_provider.dart';
@ -66,6 +71,7 @@ import 'package:marking_app/utils/request/rest_client.dart';
import 'package:percent_indicator/percent_indicator.dart'; import 'package:percent_indicator/percent_indicator.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
import 'components/do_paper_bottom_review_marks.dart';
import 'hooks/use_abnormal.dart'; import 'hooks/use_abnormal.dart';
part 'do_papers.g.dart'; part 'do_papers.g.dart';
@ -138,6 +144,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
bool _completionPromptTab = false; // tab下试题完成并提示 bool _completionPromptTab = false; // tab下试题完成并提示
bool _reviewCompletedPrompted = false; // bool _reviewCompletedPrompted = false; //
bool annotationTips = false; //
// bool _switchQueTypePrompt = false; // // bool _switchQueTypePrompt = false; //
@ -157,6 +164,10 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
fToast.init(context); fToast.init(context);
Future.delayed(const Duration(seconds: 0)).then((onValue) { Future.delayed(const Duration(seconds: 0)).then((onValue) {
ref.read(annotationGraffitiSwitchProvider.notifier).init(); ref.read(annotationGraffitiSwitchProvider.notifier).init();
//
ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], []));
//
ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG);
}); });
// //
@ -174,9 +185,8 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
screenDirectionSwitch(state.screenDirection); screenDirectionSwitch(state.screenDirection);
} else { } else {
ScreenDirection nowScreenDirection = state.screenDirection; // ScreenDirection nowScreenDirection = state.screenDirection; //
ScreenDirection theOrientation = MediaQuery.of(context).orientation == Orientation.landscape ScreenDirection theOrientation =
? ScreenDirection.HORIZONTAL_SCREEN MediaQuery.of(context).orientation == Orientation.landscape ? ScreenDirection.HORIZONTAL_SCREEN : ScreenDirection.VERTICAL_SCREEN;
: ScreenDirection.VERTICAL_SCREEN;
if (theOrientation != nowScreenDirection) { if (theOrientation != nowScreenDirection) {
screenDirectionSwitch(nowScreenDirection); screenDirectionSwitch(nowScreenDirection);
} }
@ -188,6 +198,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
setTimeOut(300, () { setTimeOut(300, () {
eventFireSub(model: SwitchKeyboardToReloadImages(true)); eventFireSub(model: SwitchKeyboardToReloadImages(true));
}); });
eventOn(callback: (BottomAnnotationSwitchCleanallOfMarking item) async {});
}); });
params = MarkingTextQuestionParams( params = MarkingTextQuestionParams(
@ -243,8 +254,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
bool isHorizontal = direction == ScreenDirection.HORIZONTAL_SCREEN; bool isHorizontal = direction == ScreenDirection.HORIZONTAL_SCREEN;
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
SystemChrome.setPreferredOrientations( SystemChrome.setPreferredOrientations([isHorizontal ? DeviceOrientation.landscapeLeft : DeviceOrientation.portraitUp]);
[isHorizontal ? DeviceOrientation.landscapeLeft : DeviceOrientation.portraitUp]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
setTimeOut(1000, () => toUpState(setState, () => annotationsFlag = true, mounted)); setTimeOut(1000, () => toUpState(setState, () => annotationsFlag = true, mounted));
}); });
@ -260,8 +270,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
return null; return null;
} }
currentQuestion!.papersUrlStr = paperUrls; currentQuestion!.papersUrlStr = paperUrls;
currentQuestion!.papersUrl = currentQuestion!.papersUrl = paperUrls.asMap().keys.map((e) => GalleryExampleItemModel(id: e.toString(), resource: paperUrls[e])).toList();
paperUrls.asMap().keys.map((e) => GalleryExampleItemModel(id: e.toString(), resource: paperUrls[e])).toList();
return currentQuestion!.papersUrl; return currentQuestion!.papersUrl;
} }
@ -426,8 +435,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
Future<void> submitTestQuestions(BuildContext theContext, MarkingTextQuestion data) async { Future<void> submitTestQuestions(BuildContext theContext, MarkingTextQuestion data) async {
Timer timer = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); Timer timer = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try { try {
if (widget.markingtype == MarkingListType.NORMAL && currentQuestion!.isException) if (widget.markingtype == MarkingListType.NORMAL && currentQuestion!.isException) return ToastUtils.showError('异常题,不允许再评分');
return ToastUtils.showError('异常题,不允许再评分');
if (currentQuestion == null) { if (currentQuestion == null) {
return ToastUtils.showError('提交失败,请退出重试。'); return ToastUtils.showError('提交失败,请退出重试。');
@ -463,15 +471,10 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
RestClient client = await getClient(); RestClient client = await getClient();
String? commentImageUrlStr; String? commentImageUrlStr;
List<String>? commentImageUrl = currentQuestion?.commentImageUrlTodo; List<String>? commentImageUrl =
if (commentImageUrl?.isEmpty ?? true) commentImageUrl = currentQuestion?.commentImageUrl; (currentQuestion?.commentImageUrl.isNotEmpty ?? false) || res?.url != null ? currentQuestion?.commentImageUrlMap.values.toList() : null;
if (commentImageUrl?.isNotEmpty ?? false) commentImageUrlStr = jsonEncode(commentImageUrl); if (commentImageUrl?.isNotEmpty ?? false) commentImageUrlStr = jsonEncode(commentImageUrl);
// bool excessContinue =
// _currentTab?.agreementExcess == null ? true : _currentTab!.agreementExcess!; // true
bool isExit = false;
MarkingTextQuestionTab? nextTag;
BaseStructureResult<bool> result = await client.submitTestQuestionsOfExam(SubmitExamParams( BaseStructureResult<bool> result = await client.submitTestQuestionsOfExam(SubmitExamParams(
widget.markingUserId, widget.markingUserId,
detailId, detailId,
@ -507,6 +510,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
e.isFinish = true; e.isFinish = true;
} }
} }
annotationTips = false;
// ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
// SnackBar( // SnackBar(
@ -758,12 +762,44 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
return ToastUtils.getFluttertoast(context: context, msg: '请先评分后提交再进入下一题'); return ToastUtils.getFluttertoast(context: context, msg: '请先评分后提交再进入下一题');
} }
print(annotationTips);
if (annotationTips && currentQuestion != null) {
//
var resFlag = await showDialog<bool>(
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: <Widget>[
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); int detailId = theId ?? (isNext ? currentQuestion!.nextId : currentQuestion!.prevId);
bool isReview = widget.isReview; bool isReview = widget.isReview;
if (theId != null && _currentTab != null && theQuestionNum != _currentTab!.questionNum) { if (theId != null && _currentTab != null && theQuestionNum != _currentTab!.questionNum) {
MarkingTextQuestionTab? _foundCrrentTab = MarkingTextQuestionTab? _foundCrrentTab = _currentTabs.firstWhereOrNull((element) => element.questionNum == theQuestionNum);
_currentTabs.firstWhereOrNull((element) => element.questionNum == theQuestionNum);
if (_foundCrrentTab != null) { if (_foundCrrentTab != null) {
_currentTab = _foundCrrentTab; _currentTab = _foundCrrentTab;
} }
@ -791,11 +827,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
// score: continueScoring hasSubtopic; cleanScore: // score: continueScoring hasSubtopic; cleanScore:
Future<void> synchroScore( Future<void> synchroScore(
{required double score, {required double score, required bool continueScoring, required bool hasSubtopic, bool allWrong = false, bool cleanScore = false}) async {
required bool continueScoring,
required bool hasSubtopic,
bool allWrong = false,
bool cleanScore = false}) async {
if (currentQuestion == null) return; if (currentQuestion == null) return;
if (cleanScore) { if (cleanScore) {
@ -879,8 +911,8 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
res.data = res.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList(); res.data = res.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList();
// 便tags key是题号 // 便tags key是题号
Map<String, MarkingTextQuestionTab> _currentTabsMap = Map<String, MarkingTextQuestionTab>.fromIterable(_currentTabs, Map<String, MarkingTextQuestionTab> _currentTabsMap =
key: (item) => item.questionNum, value: (item) => item); Map<String, MarkingTextQuestionTab>.fromIterable(_currentTabs, key: (item) => item.questionNum, value: (item) => item);
MarkingTextQuestionTab? theCurrentTab; MarkingTextQuestionTab? theCurrentTab;
String currentTagQueNum = _currentTab!.questionNum; String currentTagQueNum = _currentTab!.questionNum;
res.data!.forEach((e) { res.data!.forEach((e) {
@ -918,31 +950,25 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
if (!widget.exceptional && _currentTabs.length <= 0 && _currentTab == null) { if (!widget.exceptional && _currentTabs.length <= 0 && _currentTab == null) {
// tag为空tag数据并且为对应的tag赋值上分值步长 // tag为空tag数据并且为对应的tag赋值上分值步长
RestClient client = await getClient(); RestClient client = await getClient();
List<BaseStructureResult> res = await Future.wait([ List<BaseStructureResult> res =
client.getTestQuestionsOfTab(widget.markingUserId), await Future.wait([client.getTestQuestionsOfTab(widget.markingUserId), client.getTestQuestionsOfTabStepSize(widget.examSubjectId)]);
client.getTestQuestionsOfTabStepSize(widget.examSubjectId) BaseStructureResult<List<MarkingTextQuestionTab>> resultTab = res[0] as BaseStructureResult<List<MarkingTextQuestionTab>>;
]); BaseStructureResult<List<MarkingTextQuestionTabStepSize>> resultTabStep = res[1] as BaseStructureResult<List<MarkingTextQuestionTabStepSize>>;
BaseStructureResult<List<MarkingTextQuestionTab>> resultTab =
res[0] as BaseStructureResult<List<MarkingTextQuestionTab>>;
BaseStructureResult<List<MarkingTextQuestionTabStepSize>> resultTabStep =
res[1] as BaseStructureResult<List<MarkingTextQuestionTabStepSize>>;
if ((!resultTab.success || (resultTab.data?.isEmpty ?? true)) || if ((!resultTab.success || (resultTab.data?.isEmpty ?? true)) ||
(!resultTabStep.success || (resultTabStep.data?.isEmpty ?? true)) || (!resultTabStep.success || (resultTabStep.data?.isEmpty ?? true)) ||
(resultTabStep.data!.length < resultTab.data!.length)) { (resultTabStep.data!.length < resultTab.data!.length)) {
throw Error(); throw Error();
} }
Map<String, double> tabStepMap = Map<String, double>.fromIterable(resultTabStep.data!, Map<String, double> tabStepMap =
key: (item) => item.questionNum, value: (item) => item.scoreInterval); Map<String, double>.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 = resultTab.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList();
resultTab.data!.forEach((element) => element.setStepSize(tabStepMap[element.questionNum] ?? 1.0)); resultTab.data!.forEach((element) => element.setStepSize(tabStepMap[element.questionNum] ?? 1.0));
_currentTabs = resultTab.data!; _currentTabs = resultTab.data!;
// tabs批次下第一个没有完成数据 // tabs批次下第一个没有完成数据
currentTab = resultTab.data!.firstWhere( currentTab = resultTab.data!.firstWhere(tabQuestionNum == null ? firstWhereCall : (e) => e.questionNum == tabQuestionNum,
tabQuestionNum == null ? firstWhereCall : (e) => e.questionNum == tabQuestionNum, orElse: () => MarkingTextQuestionTab(isFinished: false, questionNum: '0.0', total: 0, finishCount: 0, isExcess: false));
orElse: () =>
MarkingTextQuestionTab(isFinished: false, questionNum: '0.0', total: 0, finishCount: 0, isExcess: false));
if (currentTab.questionNum == '0.0') { if (currentTab.questionNum == '0.0') {
// tab设置为第一个 // tab设置为第一个
@ -1025,8 +1051,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
if (hasNext) { if (hasNext) {
// tab // tab
return _currentTabs.firstWhere(firstWhereCall, return _currentTabs.firstWhere(firstWhereCall,
orElse: () => MarkingTextQuestionTab( orElse: () => MarkingTextQuestionTab(questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
} }
if (tabQuestionNum != null) { if (tabQuestionNum != null) {
@ -1036,8 +1061,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
if (resetting) { if (resetting) {
// //
MarkingTextQuestionTab theMarking = _currentTabs.firstWhere(firstWhereCall, MarkingTextQuestionTab theMarking = _currentTabs.firstWhere(firstWhereCall,
orElse: () => MarkingTextQuestionTab( orElse: () => MarkingTextQuestionTab(questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
if (theMarking.questionNum != '0.0') { if (theMarking.questionNum != '0.0') {
currentTab = theMarking; currentTab = theMarking;
} }
@ -1108,6 +1132,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
// bool flagInputKeyboardGuidePage = await FastData.getInstance().getInputKeyboardGuidePage(); // // bool flagInputKeyboardGuidePage = await FastData.getInstance().getInputKeyboardGuidePage(); //
try { try {
theRequesting = true; theRequesting = true;
RestClient client = await getClient(); RestClient client = await getClient();
MarkingTextQuestionTab? temTab; MarkingTextQuestionTab? temTab;
bool isNormal = !widget.exceptional; bool isNormal = !widget.exceptional;
@ -1116,8 +1141,6 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
MarkingTextQuestionTab? oldCurrentTab = _currentTab; MarkingTextQuestionTab? oldCurrentTab = _currentTab;
temTab = await getTabsData(tabQuestionNum: tabQuestionNum, resetting: resetting); // tag tag temTab = await getTabsData(tabQuestionNum: tabQuestionNum, resetting: resetting); // tag tag
print('当前选中类型:${temTab.questionNum}');
MarkingTextQuestionTabParams theParam = tabParams.setQuestionNum( MarkingTextQuestionTabParams theParam = tabParams.setQuestionNum(
tab: temTab, tab: temTab,
locaQuestionNum: oldCurrentTab?.questionNum, locaQuestionNum: oldCurrentTab?.questionNum,
@ -1140,11 +1163,16 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
setTimeOut(300, () => ToastUtils.showError('请求错诶,请重试')); setTimeOut(300, () => ToastUtils.showError('请求错诶,请重试'));
throw Error(); throw Error();
} }
//
ref.read(doPaperBottomReviewMarksProvider.notifier).setState(ReviewMarksBottomBtnsEnum.DRAG);
//
ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal([], []));
currentQuestion = result.data; currentQuestion = result.data;
if (temTab != null) { if (temTab != null) {
result.data!.scoreInterval = temTab.scoreInterval ?? 1; result.data!.scoreInterval = temTab.scoreInterval ?? 1;
MarkingZoom? markingZoom = await UseZoomImageHistoryUtils.getZoomImageInfo( MarkingZoom? markingZoom =
widget.markingUserId.toString() + '-' + (currentQuestion?.questionNum.toString() ?? '')); await UseZoomImageHistoryUtils.getZoomImageInfo(widget.markingUserId.toString() + '-' + (currentQuestion?.questionNum.toString() ?? ''));
if (markingZoom != null) { if (markingZoom != null) {
imageScale = double.parse(markingZoom.scale.toStringAsFixed(2)); imageScale = double.parse(markingZoom.scale.toStringAsFixed(2));
imagePosition = Offset( imagePosition = Offset(
@ -1156,60 +1184,8 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
imageScale = 1; imageScale = 1;
imagePosition = Offset(0, 0); 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; bool hasSub = currentQuestion!.subQuestionDetailList.isNotEmpty;
activeQuestIndex = 0; // activeQuestIndex = 0; //
double fullScore; double fullScore;
@ -1232,8 +1208,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
if (firstComeIn) setTimeOut(2000, () => firstComeIn = false); if (firstComeIn) setTimeOut(2000, () => firstComeIn = false);
if (ref.read(markingSubtopicSwitchingProvider.notifier).state != activeQuestIndex) { if (ref.read(markingSubtopicSwitchingProvider.notifier).state != activeQuestIndex) {
// //
Future.delayed( Future.delayed(Duration.zero, () => ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex));
Duration.zero, () => ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex));
} }
if (currentQuestion != null && widget.markingtype == MarkingListType.EXCEPTIONAL) { if (currentQuestion != null && widget.markingtype == MarkingListType.EXCEPTIONAL) {
BaseStructureResult<ExceptionInfo> res = await client.getMarkingQuestionsErrorInfo(currentQuestion!.id); BaseStructureResult<ExceptionInfo> res = await client.getMarkingQuestionsErrorInfo(currentQuestion!.id);
@ -1250,6 +1225,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
} }
} }
Future.delayed(Duration.zero, () => annotationTips = false);
// getMarkingQuestionsErrorInfo // getMarkingQuestionsErrorInfo
return currentQuestion; return currentQuestion;
} catch (e) { } catch (e) {
@ -1435,8 +1411,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
bool isNormal = !widget.exceptional; // bool isNormal = !widget.exceptional; //
bool notNextTest = data.nextId == 0; // bool notNextTest = data.nextId == 0; //
// //
var pressedNextTest = var pressedNextTest = notNextTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh(isNext: true));
notNextTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh(isNext: true));
bool notHasPreviousTest = data.prevId == 0; bool notHasPreviousTest = data.prevId == 0;
/** /**
@ -1501,8 +1476,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
color: const Color.fromRGBO(148, 163, 182, 1), color: const Color.fromRGBO(148, 163, 182, 1),
), ),
), ),
if (_currentTab!.isExcess && if (_currentTab!.isExcess && _currentTab!.finishCount > _currentTab!.total)
_currentTab!.finishCount > _currentTab!.total)
Container( Container(
margin: EdgeInsets.only(left: 4.w), margin: EdgeInsets.only(left: 4.w),
child: Row( child: Row(
@ -1513,8 +1487,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
color: const Color.fromRGBO(148, 163, 182, 1), color: const Color.fromRGBO(148, 163, 182, 1),
), ),
quickText( quickText(
(_currentTab!.finishCount - _currentTab!.total) (_currentTab!.finishCount - _currentTab!.total).toString(),
.toString(),
size: isBroadwise ? 18.sp : 14.sp, size: isBroadwise ? 18.sp : 14.sp,
color: Color.fromRGBO(251, 144, 84, 1), color: Color.fromRGBO(251, 144, 84, 1),
), ),
@ -1540,19 +1513,16 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
), ),
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
if (model.hideQuestionId && if (model.hideQuestionId && model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN)
model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN)
InkWell( InkWell(
onTap: () { onTap: () {
Clipboard.setData(ClipboardData(text: data.paperNum ?? '')) Clipboard.setData(ClipboardData(text: data.paperNum ?? '')).then((value) {
.then((value) {
ToastUtils.showSuccess('试卷编号已复制'); ToastUtils.showSuccess('试卷编号已复制');
}); });
}, },
child: Row( child: Row(
children: [ children: [
quickText('试卷编号: ', quickText('试卷编号: ', size: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
size: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
quickText( quickText(
data.paperNum ?? '', data.paperNum ?? '',
size: 16.sp, size: 16.sp,
@ -1585,8 +1555,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
color: const Color.fromRGBO(4, 201, 208, 1), color: const Color.fromRGBO(4, 201, 208, 1),
), ),
), ),
if (isBroadwise && widget.markingtype == MarkingListType.EXCEPTIONAL || if (isBroadwise && widget.markingtype == MarkingListType.EXCEPTIONAL || data.isException)
data.isException)
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 2.h), padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 2.h),
color: const Color.fromRGBO(245, 108, 108, 0.236), color: const Color.fromRGBO(245, 108, 108, 0.236),
@ -1630,18 +1599,14 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
size: isBroadwise ? 15.sp : 12.sp, size: isBroadwise ? 15.sp : 12.sp,
), ),
SizedBox(width: 1.w), SizedBox(width: 1.w),
quickText('继续阅卷', quickText('继续阅卷', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
], ],
), ),
), ),
SizedBox(width: 10.w), SizedBox(width: 10.w),
InkWell( InkWell(
onTap: () { onTap: () {
ref ref.read(ratingProgressProvider.notifier).setState(EndDrawerViewEnum.REVIEW_RECORD);
.read(ratingProgressProvider.notifier)
.setState(EndDrawerViewEnum.REVIEW_RECORD);
scaffoldKey.currentState?.openEndDrawer(); scaffoldKey.currentState?.openEndDrawer();
}, },
child: Row( child: Row(
@ -1652,9 +1617,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
size: isBroadwise ? 15.sp : 12.sp, size: isBroadwise ? 15.sp : 12.sp,
), ),
SizedBox(width: 1.w), SizedBox(width: 1.w),
quickText('阅卷记录', quickText('阅卷记录', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
], ],
), ),
), ),
@ -1666,9 +1629,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
), ),
InkWell( InkWell(
onTap: () { onTap: () {
ref ref.read(ratingProgressProvider.notifier).setState(EndDrawerViewEnum.RATING_PROGRESS);
.read(ratingProgressProvider.notifier)
.setState(EndDrawerViewEnum.RATING_PROGRESS);
scaffoldKey.currentState?.openEndDrawer(); scaffoldKey.currentState?.openEndDrawer();
}, },
child: Row( child: Row(
@ -1679,9 +1640,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
size: isBroadwise ? 15.sp : 12.sp, size: isBroadwise ? 15.sp : 12.sp,
), ),
SizedBox(width: 1.w), SizedBox(width: 1.w),
quickText('评分进度', quickText('评分进度', color: const Color.fromRGBO(80, 87, 103, 1), size: isBroadwise ? 15.sp : 12.sp),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
], ],
), ),
), ),
@ -1690,8 +1649,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
InkWell( InkWell(
onTap: () { onTap: () {
if (data.isException) { if (data.isException) {
return ToastUtils.getFluttertoast( return ToastUtils.getFluttertoast(context: context, msg: '当前试题已为异常题,无需重复提交');
context: context, msg: '当前试题已为异常题,无需重复提交');
} }
toUpState(setState, () => showAbnormal = true, mounted); toUpState(setState, () => showAbnormal = true, mounted);
}, },
@ -1817,17 +1775,14 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
return InkWell( return InkWell(
onTap: () { onTap: () {
double? getScore = quest.subQuestionGotScore; double? getScore = quest.subQuestionGotScore;
ref ref.read(markingSubtopicSwitchingProvider.notifier).setVal(index);
.read(markingSubtopicSwitchingProvider.notifier)
.setVal(index);
toUpState(setState, () { toUpState(setState, () {
activeQuestIndex = index; activeQuestIndex = index;
// TODO // TODO
// pictureOverviewKey.currentState?.jumpToPage(activeQuestIndex); // pictureOverviewKey.currentState?.jumpToPage(activeQuestIndex);
questScore = getScore?.toString() ?? ''; questScore = getScore?.toString() ?? '';
hasZeroPointFive = hasZeroPointFive = questScore != '' && getScore! >= quest.subQuestionScore;
questScore != '' && getScore! >= quest.subQuestionScore;
}, mounted); }, mounted);
}, },
child: Container( child: Container(
@ -1848,8 +1803,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
alignment: const FractionalOffset(0.5, 1.78), alignment: const FractionalOffset(0.5, 1.78),
children: [ children: [
Container( Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
horizontal: 4.w, vertical: 8.h),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
color: !activeIndex color: !activeIndex
@ -1871,9 +1825,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: activeIndex color: activeIndex ? Colors.white : const Color.fromRGBO(80, 87, 103, 1),
? Colors.white
: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 13.sp, fontSize: 13.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@ -1884,22 +1836,18 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
child: quickText( child: quickText(
'(${getDoubleRemoveZero(data.subQuestionDetailList[index].subQuestionScore)})', '(${getDoubleRemoveZero(data.subQuestionDetailList[index].subQuestionScore)})',
size: 11.sp, size: 11.sp,
color: activeIndex color:
? Colors.white activeIndex ? Colors.white : const Color.fromRGBO(80, 87, 103, 1)),
: const Color.fromRGBO(
80, 87, 103, 1)),
) )
], ],
)), )),
if (activeIndex) if (activeIndex)
Icon(Icons.arrow_drop_down_outlined, Icon(Icons.arrow_drop_down_outlined,
color: const Color.fromRGBO(46, 91, 255, 1), color: const Color.fromRGBO(46, 91, 255, 1), size: 20.sp)
size: 20.sp)
], ],
), ),
Container( Container(
padding: padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
getDoubleRemoveZero(quest.subQuestionGotScore, '请评分'), getDoubleRemoveZero(quest.subQuestionGotScore, '请评分'),
@ -1945,8 +1893,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
), ),
child: Text( child: Text(
'>>', '>>',
style: style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp),
TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp),
), ),
)), )),
onHorizontalDragEnd: (detail) { onHorizontalDragEnd: (detail) {
@ -1962,9 +1909,10 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
children: [ children: [
// //
Container( Container(
margin: EdgeInsets.only(top: 6.h), // margin: EdgeInsets.only(top: 6.h),
padding: EdgeInsets.symmetric(horizontal: 1.w), padding: EdgeInsets.symmetric(horizontal: 1.w),
child: PictureOverview( child: PictureOverview(
data: data,
questionNum: data.questionNum, questionNum: data.questionNum,
markingUserId: widget.markingUserId, markingUserId: widget.markingUserId,
key: pictureOverviewKey, key: pictureOverviewKey,
@ -1973,21 +1921,14 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
annotationsFlag: annotationSwitch, annotationsFlag: annotationSwitch,
commentImageMap: data.commentImageUrlMap, commentImageMap: data.commentImageUrlMap,
testQuestionNumber: widget.markingUserId.toString() + '-' + data.questionNum, testQuestionNumber: widget.markingUserId.toString() + '-' + data.questionNum,
imageItems: data.getImageData(), imageItems: data.studentAnswerList,
callAnnotationTips: () {
//
annotationTips = true;
},
), ),
), ),
//
// if (!showSetingFlag &&
// !widget.exceptional &&
// currentQuestion != null &&
// annotationsFlag &&
// !showAbnormal &&
// !showStandardAnswer)
// Positioned(
// left: 0,
// bottom: 0,
// child: BottomAnnotationSwitch(maxWidth: maxWidth - 1.5.w),
// ),
// //
if (!hasSubtopic) if (!hasSubtopic)
Positioned( Positioned(
@ -2000,10 +1941,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1), color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1),
child: Container( child: Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: (data.score == null || horizontal: (data.score == null || (getDoubleRemoveZero(data.score ?? 0)).length >= 2) ? 4.w : 12.w,
(getDoubleRemoveZero(data.score ?? 0)).length >= 2)
? 4.w
: 12.w,
vertical: 6.h), vertical: 6.h),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
@ -2029,15 +1967,11 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1), color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1),
child: Container( child: Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: (data.score == null || horizontal: (data.score == null || (getDoubleRemoveZero(data.score ?? 0)).length >= 2) ? 4.w : 12.w,
(getDoubleRemoveZero(data.score ?? 0)).length >= 2)
? 4.w
: 12.w,
vertical: 6.h), vertical: 6.h),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
getDoubleRemoveZero(data.score, getDoubleRemoveZero(data.score, '请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}'),
'请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}'),
style: TextStyle( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
color: const Color.fromRGBO(46, 91, 255, 1), color: const Color.fromRGBO(46, 91, 255, 1),
@ -2047,26 +1981,23 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
), ),
), ),
// //
if (widget.markingtype != MarkingListType.EXCEPTIONAL && if (widget.markingtype != MarkingListType.EXCEPTIONAL && !_theOldAnnotationGraffiti && !notHasPreviousTest)
!_theOldAnnotationGraffiti &&
!notHasPreviousTest)
Positioned( Positioned(
left: 3.w, left: 3.w,
top: ScreenUtil().setHeight(MediaQuery.of(context).size.height) / 2 * 0.87, top: ScreenUtil().setHeight(MediaQuery.of(context).size.height) / 2 * 0.87,
child: FloatingActionButton( child: FloatingActionButton(
tooltip: '前往上一题', tooltip: '前往上一题',
backgroundColor: notHasPreviousTest backgroundColor:
? const Color.fromRGBO(24, 32, 32, 0.04) notHasPreviousTest ? const Color.fromRGBO(24, 32, 32, 0.04) : const Color.fromRGBO(24, 32, 32, 0.1),
: const Color.fromRGBO(24, 32, 32, 0.1),
focusColor: Theme.of(context).primaryColor, focusColor: Theme.of(context).primaryColor,
elevation: 0, elevation: 0,
onPressed: notHasPreviousTest onPressed: notHasPreviousTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh()),
? null
: () => easyThrottle('TestQuestionSwitch', () => refresh()),
child: const Icon(Icons.arrow_back_ios, color: Colors.white), child: const Icon(Icons.arrow_back_ios, color: Colors.white),
heroTag: 'other', heroTag: 'other',
), ),
), ),
//
DoPaperBottomReviewMarks(),
// //
if (!_theOldAnnotationGraffiti && pressedNextTest != null && isNormal) if (!_theOldAnnotationGraffiti && pressedNextTest != null && isNormal)
Positioned( Positioned(
@ -2075,9 +2006,8 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
child: FloatingActionButton( child: FloatingActionButton(
elevation: 0, elevation: 0,
tooltip: '点击前往下一题', tooltip: '点击前往下一题',
backgroundColor: notNextTest backgroundColor:
? const Color.fromRGBO(24, 32, 32, 0.04) notNextTest ? const Color.fromRGBO(24, 32, 32, 0.04) : const Color.fromRGBO(24, 32, 32, 0.1),
: const Color.fromRGBO(24, 32, 32, 0.1),
foregroundColor: Colors.white, foregroundColor: Colors.white,
onPressed: pressedNextTest, onPressed: pressedNextTest,
child: const Icon(Icons.arrow_forward_ios, color: Colors.white), child: const Icon(Icons.arrow_forward_ios, color: Colors.white),
@ -2169,8 +2099,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
// //
$AbnormalBox( $AbnormalBox(
businessHandle: (bool flag, String? reasonKey, String? otherReasons) => businessHandle: (bool flag, String? reasonKey, String? otherReasons) => initiateException(flag, reasonKey, otherReasons),
initiateException(flag, reasonKey, otherReasons),
isBroadwise: isBroadwise, isBroadwise: isBroadwise,
showAbnormal: !showAbnormal, showAbnormal: !showAbnormal,
), ),
@ -2202,8 +2131,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
eventFireSub(model: SwitchKeyboardToReloadImages(true)); eventFireSub(model: SwitchKeyboardToReloadImages(true));
}); });
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false); ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
ToastUtils.showSuccess(newOpenAuxiliary ? '开启双栏打分' : '关闭双栏打分', ToastUtils.showSuccess(newOpenAuxiliary ? '开启双栏打分' : '关闭双栏打分', duration: const Duration(milliseconds: 300));
duration: const Duration(milliseconds: 300));
}); });
}, },
// 线 // 线
@ -2212,8 +2140,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
width: isBroadwise ? 18.w : 42.w, width: isBroadwise ? 18.w : 42.w,
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius: BorderRadius.only(topLeft: Radius.circular(8.w), bottomLeft: Radius.circular(8.w)),
BorderRadius.only(topLeft: Radius.circular(8.w), bottomLeft: Radius.circular(8.w)),
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
), ),
child: Row( child: Row(
@ -2247,8 +2174,7 @@ class _MarkingPapersState extends ConsumerState<DoPapers>
tabName: _currentTab?.questionNum ?? '', tabName: _currentTab?.questionNum ?? '',
tabs: _currentTabs, tabs: _currentTabs,
direction: keyboardModel?.screenDirection ?? ScreenDirection.HORIZONTAL_SCREEN, direction: keyboardModel?.screenDirection ?? ScreenDirection.HORIZONTAL_SCREEN,
call: (int detailId, String selectedQuesiontNum) => call: (int detailId, String selectedQuesiontNum) => refresh(theId: detailId, theQuestionNum: selectedQuesiontNum),
refresh(theId: detailId, theQuestionNum: selectedQuesiontNum),
markingUserId: widget.markingUserId, markingUserId: widget.markingUserId,
questionNum: _currentTab?.questionNum, questionNum: _currentTab?.questionNum,
), ),
@ -2429,10 +2355,8 @@ Widget $abnormalBox(
child: TextField( child: TextField(
controller: controller, controller: controller,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
onEditingComplete: () => easyThrottle( onEditingComplete: () => easyThrottle('Abnormal_submission_confirmation_button',
'Abnormal_submission_confirmation_button', () => _useAbnormal.submit(context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason))),
() => _useAbnormal.submit(context, controller,
(reasonType, reason) => businessHandle(true, reasonType, reason))),
maxLines: 15, maxLines: 15,
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
decoration: InputDecoration( decoration: InputDecoration(
@ -2452,8 +2376,7 @@ Widget $abnormalBox(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
InkWell( InkWell(
onTap: () => easyThrottle( onTap: () => easyThrottle('Abnormal_submission_confirmation_button', () => businessHandle(false, null, null)),
'Abnormal_submission_confirmation_button', () => businessHandle(false, null, null)),
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
margin: EdgeInsets.only(right: 16.w), margin: EdgeInsets.only(right: 16.w),
@ -2483,8 +2406,7 @@ Widget $abnormalBox(
InkWell( InkWell(
onTap: () => easyThrottle( onTap: () => easyThrottle(
'Abnormal_submission_confirmation_button', 'Abnormal_submission_confirmation_button',
() => _useAbnormal.submit( () => _useAbnormal.submit(context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason)),
context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason)),
), ),
// () { // () {
@ -2582,8 +2504,7 @@ class StandardAnswerRegion extends StatelessWidget {
/// ///
@hwidget @hwidget
Widget $abnormalQuestionInfo( Widget $abnormalQuestionInfo({required bool hasSubtopic, required bool isBroadwise, required bool show, double? score, ExceptionInfo? info}) {
{required bool hasSubtopic, required bool isBroadwise, required bool show, double? score, ExceptionInfo? info}) {
final _useFlagAnimation = useState(true); final _useFlagAnimation = useState(true);
AnimationController _useAnimationHorizontal = useAnimationController( AnimationController _useAnimationHorizontal = useAnimationController(
initialValue: 300, initialValue: 300,
@ -2675,14 +2596,12 @@ Widget $abnormalQuestionInfo(
Row( Row(
children: [ children: [
if ((info?.studentName.length ?? 0) > 0) if ((info?.studentName.length ?? 0) > 0)
quickText('考生:${info!.studentName}', quickText('考生:${info!.studentName}', color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
// overflow: TextOverflow.clip, // overflow: TextOverflow.clip,
), ),
SizedBox(width: 3.w), SizedBox(width: 3.w),
if ((info?.studentExamNum.length ?? 0) > 0) if ((info?.studentExamNum.length ?? 0) > 0)
quickText('考号:${info!.studentExamNum}', quickText('考号:${info!.studentExamNum}', color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
// overflow: TextOverflow.clip, // overflow: TextOverflow.clip,
), ),
], ],
@ -2716,8 +2635,7 @@ Widget $abnormalQuestionInfo(
/// ///
@hwidget @hwidget
Widget $arbitrationQuestionInfo( Widget $arbitrationQuestionInfo({required bool show, required bool isBroadwise, required bool hasSubtopic, required List<HistoricalScoring> data}) {
{required bool show, required bool isBroadwise, required bool hasSubtopic, required List<HistoricalScoring> data}) {
final _useFlagAnimation = useState(true); final _useFlagAnimation = useState(true);
AnimationController _useAnimationHorizontal = useAnimationController( AnimationController _useAnimationHorizontal = useAnimationController(
initialValue: 300, initialValue: 300,

View File

@ -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<DoPaperBottomReviewMarksHandle, ReviewMarksBottomBtnsEnum>(
(ref) => DoPaperBottomReviewMarksHandle(ReviewMarksBottomBtnsEnum.DRAG),
);
class DoPaperBottomReviewMarksHandle extends StateNotifier<ReviewMarksBottomBtnsEnum> {
DoPaperBottomReviewMarksHandle(ReviewMarksBottomBtnsEnum val) : super(val);
void setState(ReviewMarksBottomBtnsEnum val) => state = val;
}

View File

@ -0,0 +1,33 @@
/*
* @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 'dart:ui';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../../components/PictureOverview.dart';
//
final drawMarkingProvider =
StateNotifierProvider<DrawMarkingProviderHandle, DrawMarkingVal>((ref) => DrawMarkingProviderHandle(DrawMarkingVal([], [])));
class DrawMarkingProviderHandle extends StateNotifier<DrawMarkingVal> {
DrawMarkingProviderHandle(DrawMarkingVal val) : super(val);
void setState(DrawMarkingVal val) {
state = val;
}
}
class DrawMarkingVal {
List<GestureRecording> data;
List<Offset?> offsets;
DrawMarkingVal(this.data, this.offsets);
}

View File

@ -22,8 +22,8 @@ import 'package:marking_app/utils/request/rest_client.dart';
// API // API
final uploadFileProvider = StateNotifierProvider<UploadFileProviderHandle, UploadImgSecretKey>( final uploadFileProvider =
(ref) => UploadFileProviderHandle(UploadImgSecretKey())); StateNotifierProvider<UploadFileProviderHandle, UploadImgSecretKey>((ref) => UploadFileProviderHandle(UploadImgSecretKey()));
class UploadFileProviderHandle extends StateNotifier<UploadImgSecretKey> with CommonMixin { class UploadFileProviderHandle extends StateNotifier<UploadImgSecretKey> with CommonMixin {
// Minio? _minio; // Minio? _minio;
@ -109,24 +109,35 @@ class UploadFileProviderHandle extends StateNotifier<UploadImgSecretKey> with Co
Future<FileResult?> getUploadFileConfig(UploadFileInterfaceConfig uploadConfig, File fileData) async { Future<FileResult?> getUploadFileConfig(UploadFileInterfaceConfig uploadConfig, File fileData) async {
Dio dio = Dio(); Dio dio = Dio();
dio.options.contentType = null;
try { try {
late Response response; late Response response;
final bytes = await fileData.readAsBytes(); final bytes = await fileData.readAsBytes();
if (uploadConfig.uploadMethod == "PUT") { if (uploadConfig.uploadMethod == "PUT") {
response = await dio.put(uploadConfig.uploadUri!, response = await dio.put(
data: Stream.fromIterable(bytes.map((e) => [e])), uploadConfig.uploadUri!,
options: Options(headers: { data: Stream.fromIterable(bytes.map((e) => [e])),
options: Options(
contentType: null,
headers: {
Headers.contentLengthHeader: bytes.length, // Set the content-length. Headers.contentLengthHeader: bytes.length, // Set the content-length.
HttpHeaders.contentTypeHeader: 'image/png', // HttpHeaders.contentTypeHeader: 'image/png',
})); },
),
);
} else if (uploadConfig.uploadMethod == "POST") { } else if (uploadConfig.uploadMethod == "POST") {
response = await dio.post(uploadConfig.uploadUri!, response = await dio.post(
data: Stream.fromIterable(bytes.map((e) => [e])), uploadConfig.uploadUri!,
options: Options(headers: { data: Stream.fromIterable(bytes.map((e) => [e])),
options: Options(
contentType: null,
headers: {
Headers.contentLengthHeader: bytes.length, // Set the content-length. Headers.contentLengthHeader: bytes.length, // Set the content-length.
HttpHeaders.contentTypeHeader: 'image/png', // HttpHeaders.contentTypeHeader: 'image/png',
})); },
),
);
} }
print('文件上传成功:${response.data}'); print('文件上传成功:${response.data}');
if ([200, 201, 204].contains(response.statusCode)) { if ([200, 201, 204].contains(response.statusCode)) {

View File

@ -9,15 +9,16 @@
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.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/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/app_upgrade/model/UpdateAppEvent.dart';
import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/index.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path_provider/path_provider.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 { class DownloadApk {
/// ///
@ -58,26 +59,45 @@ class DownloadApk {
debugPrint('make sure the apk file is set'); debugPrint('make sure the apk file is set');
return false; return false;
} }
try {
await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
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, fontWeight: FontWeight.bold)),
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) {}
});
Map<Permission, PermissionStatus> statuses = await [Permission.storage].request(); print('安装执行完成了..............0.0');
} catch (e) {
if (statuses[Permission.storage]!.isGranted) { print('安装进入报错....');
// String? result = await InstallPlugin.installApk(_apkFilePath, appId: event.packageName).catchError((error) { print(e);
// debugPrint('install apk error: $error');
// });
// 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!');
} }
return false; return false;
@ -87,7 +107,7 @@ class DownloadApk {
static void showDownloadProgress(context, num received, num total, WidgetRef ref) { static void showDownloadProgress(context, num received, num total, WidgetRef ref) {
if (total != -1) { if (total != -1) {
double progress = double.parse((received / total).toStringAsFixed(2)); double progress = double.parse((received / total).toStringAsFixed(2));
debugPrint('下载进度$progress'); // debugPrint('下载进度$progress');
ref.read(upgradeProvider.notifier).setVal(progress); ref.read(upgradeProvider.notifier).setVal(progress);
} }
} }

View File

@ -14,8 +14,6 @@
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-01-12 15:08:43 * @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:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:marking_app/provider/upgrade_provider.dart'; import 'package:marking_app/provider/upgrade_provider.dart';
@ -27,6 +25,7 @@ import 'package:marking_app/utils/my_text.dart';
import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
class UpdateDialog extends Dialog { class UpdateDialog extends Dialog {
@ -145,6 +144,19 @@ class DownloadButton extends ConsumerWidget {
final String deviceInfo; final String deviceInfo;
const DownloadButton(this.updateAppEvent, {required this.deviceInfo, Key? key}) : super(key: key); const DownloadButton(this.updateAppEvent, {required this.deviceInfo, Key? key}) : super(key: key);
//
Future<bool> 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 @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(upgradeProvider); final count = ref.watch(upgradeProvider);
@ -161,12 +173,12 @@ class DownloadButton extends ConsumerWidget {
]), ]),
), ),
child: MaterialButton( 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) { if (deviceInfo == "android" && updateAppEvent.equipment == Equipment.android) {
bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(); //
bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context, updateAppEvent);
if (flag) { if (flag) {
flag = await DownloadApk.installApk(context, updateAppEvent, ref); flag = await DownloadApk.installApk(context, updateAppEvent, ref);
if (!flag) { if (!flag) {
print('执行到了重置更新按钮的地方....'); print('执行到了重置更新按钮的地方....');
ref.read(upgradeProvider.notifier).clean(); // ref.read(upgradeProvider.notifier).clean(); //
@ -176,8 +188,8 @@ class DownloadButton extends ConsumerWidget {
} }
return; return;
} }
await FlutterClipboard.copy(updateAppEvent.link); // await FlutterClipboard.copy(updateAppEvent.link);
setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装')); // setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装'));
} else if (deviceInfo == "ios" && updateAppEvent.equipment == Equipment.ios) { } else if (deviceInfo == "ios" && updateAppEvent.equipment == Equipment.ios) {
try { try {
await launchUrlString(updateAppEvent.link); await launchUrlString(updateAppEvent.link);

View File

@ -6,42 +6,137 @@
* @LastEditors: wangyang 1147192855@qq.com * @LastEditors: wangyang 1147192855@qq.com
* @LastEditTime: 2022-08-01 14:08:57 * @LastEditTime: 2022-08-01 14:08:57
*/ */
import 'package:marking_app/utils/index.dart'; import 'package:app_installer/app_installer.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:url_launcher/url_launcher.dart';
import 'model/UpdateAppEvent.dart';
class UpgradePermission { class UpgradePermission {
final String _flatform; final String _flatform;
const UpgradePermission(this._flatform); const UpgradePermission(this._flatform);
/// ///
Future<bool> checkPermission() async { /// noExecutions
// if (_flatform == 'android') { Future<bool> 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;
// return await Permission.storage.request().isGranted; if (status.isDenied) {
// } else { //
// return true;
// }
if (_flatform == 'android') { await showDialog<bool>(
final status = await Permission.storage.status; context: context,
if (status != PermissionStatus.granted) { barrierDismissible: false,
final result = await Permission.storage.request(); builder: (BuildContext context) {
if (result == PermissionStatus.granted) { return AlertDialog(
return true; title: const Text("权限提示"),
} content: const Text("无法获取存储权限,请同意获取设备存储权限"),
if (status == PermissionStatus.denied) { actions: [
ToastUtils.showError('拒绝了保存安装权限'); MaterialButton(
} color: Theme.of(context).primaryColor,
child: const Text("同意", style: TextStyle(color: Colors.white)),
onPressed: () => Navigator.of(context).pop(),
),
],
);
},
);
if (status == PermissionStatus.permanentlyDenied) { if (noExecutions < 2) return checkPermission(context, updateAppEvent, ++noExecutions);
ToastUtils.showError('用户永久拒绝保存安装权限,请前往设置权限'); // 2
}
} else {
return true;
}
} else {
return true;
} }
//
bool? res = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("权限提示"),
content: const Text("储存权限被永久拒绝,并且不再提示。请前往设置页面同意储存权限"),
actions: [
MaterialButton(
color: Colors.green.shade900,
child: const Text("其它方式更新", style: TextStyle(color: Colors.white)),
onPressed: () => Navigator.of(context).pop(false),
),
MaterialButton(
color: Theme.of(context).primaryColor,
child: const Text("前往设置", style: TextStyle(color: Colors.white)),
onPressed: () => Navigator.of(context).pop(true),
),
],
);
},
);
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; return false;
} }
//
static Future<String?> showCustomModalBottomSheet(context, List<String> options) async {
return showModalBottomSheet<String>(
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),
);
},
),
),
]),
);
},
);
}
} }

View File

@ -190,6 +190,10 @@ abstract class RestClient {
@the_retrofit.GET("/api/marking/rating-info") @the_retrofit.GET("/api/marking/rating-info")
Future<BaseStructureResult<List<RatingProgressModel>>> getMarkingRatingInfo(@the_retrofit.Query("markingUserId") int id); Future<BaseStructureResult<List<RatingProgressModel>>> getMarkingRatingInfo(@the_retrofit.Query("markingUserId") int id);
// =>
@the_retrofit.GET("/api/Upload")
Future<BaseStructureResult<UploadFileInterfaceConfig>> getMarkingUploadFile(@the_retrofit.Queries() UploadFileInterfaceConfigParams params);
// ------------------------------------------ ------------------------------------------ // ------------------------------------------ ------------------------------------------
// => // =>

View File

@ -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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.106 version: 1.0.107+2
environment: environment:
sdk: ">=2.17.1 <3.0.0" sdk: ">=2.17.1 <3.0.0"
@ -114,6 +114,8 @@ dependencies:
flutter_staggered_grid_view: ^0.6.2 flutter_staggered_grid_view: ^0.6.2
# 饼图 # 饼图
flutter_echart: ^2.0.0 flutter_echart: ^2.0.0
app_installer: ^1.1.0
dev_dependencies: dev_dependencies: