Merge branch 'marking_annotations_04_29'
This commit is contained in:
commit
88dd4c4c16
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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"/>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
enum ReviewMarksBottomBtnsEnum {
|
||||||
|
DRAG, // 拖动
|
||||||
|
HANDWRITING, // 笔迹
|
||||||
|
RETURN_PREVIOUS_LEVEL, // 返回上一级
|
||||||
|
CLEAR_ALL // 清空全部
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,3 +41,11 @@ class GestureHandwritingRecording {
|
||||||
required this.intervalTime,
|
required this.intervalTime,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 笔记还原页面 查看原稿
|
||||||
|
*/
|
||||||
|
class ShowStudentMmanuscript {
|
||||||
|
bool showManuscript; // 查看原稿
|
||||||
|
ShowStudentMmanuscript(this.showManuscript);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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: '提交失败');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
// ------------------------------------------ 作业 ------------------------------------------
|
// ------------------------------------------ 作业 ------------------------------------------
|
||||||
|
|
||||||
// 作业 => 作业列表
|
// 作业 => 作业列表
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue