完成 作业首页更改和作业笔迹还原默认两倍速 和查看原稿功能

This commit is contained in:
1147192855@qq.com 2024-05-17 15:41:04 +08:00
parent 8287518fc1
commit 1f2e5dbb56
5 changed files with 850 additions and 166 deletions

View File

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

View File

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

View File

@ -1,19 +1,568 @@
// import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
// import 'package:flutter_hooks/flutter_hooks.dart';
// import 'package:flutter_screenutil/flutter_screenutil.dart';
// import 'package:functional_widget_annotation/functional_widget_annotation.dart';
// import 'package:marking_app/common/mixin/common.dart';
// import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart';
// import 'package:marking_app/common/model/marking/marking_list_params.dart';
// import 'package:marking_app/pages/common/event_bus_mixin.dart';
// import 'package:marking_app/routes/RouterManager.dart';
// import 'package:marking_app/utils/index.dart';
// import 'package:marking_app/utils/my_text.dart';
// import 'package:flutter_easyrefresh/easy_refresh.dart';
// import 'package:badges/badges.dart' as badges;
// part 'job_home.g.dart';
// class JobHome extends StatefulWidget {
// const JobHome({super.key});
// @override
// State<JobHome> createState() => _JobHomeState();
// }
// class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin {
// @override
// bool get wantKeepAlive => true;
// late LinkHeaderNotifier _linkNotifier;
// late ValueNotifier<bool> _secondFloorOpen;
// @override
// void initState() {
// getData();
// eventOn(callback: (JobHomeRefreshBus item) => getData());
// _linkNotifier = LinkHeaderNotifier();
// _secondFloorOpen = ValueNotifier<bool>(false);
// super.initState();
// }
// @override
// void dispose() {
// eventCancel();
// _linkNotifier.dispose();
// _secondFloorOpen.dispose();
// super.dispose();
// }
// Future<int> getData() async {
// try {
// var _client = await getClient();
// var _result = await _client.getJobsByPage(MarkingListParams(
// isFinish: false,
// page: 1,
// limit: 1,
// pageType: 0,
// ));
// var data = _result.data?.total ?? 0;
// eventFire(model: QuantityToBeReviewedData(data));
// return data;
// } catch (e) {
// return 0;
// }
// }
// @override
// Widget build(BuildContext context) {
// super.build(context);
// return AnnotatedRegion(
// value: const SystemUiOverlayStyle(
// systemNavigationBarColor: Color(0xFF000000),
// systemNavigationBarDividerColor: null,
// statusBarColor: Colors.white,
// systemNavigationBarIconBrightness: Brightness.light,
// statusBarIconBrightness: Brightness.dark,
// statusBarBrightness: Brightness.light,
// ),
// child: SizedBox(
// height: ScreenUtil().screenHeight,
// width: ScreenUtil().screenWidth,
// child: Column(
// children: [
// //
// SecondFloorWidget(_linkNotifier, _secondFloorOpen, refreshCall: () => eventFire(model: JobHomeRefreshBus())),
// Expanded(
// child: EasyRefresh.custom(
// header: LinkHeader(
// _linkNotifier,
// extent: 70.0,
// triggerDistance: 70.0,
// completeDuration: Duration(milliseconds: 500),
// ),
// onRefresh: () async {
// if (_secondFloorOpen.value) return;
// // await Future.delayed(Duration(seconds: 2), () {
// // if (mounted) {
// // setState(() {
// // _count = 20;
// // });
// // }
// // });
// },
// onLoad: () async {
// // await Future.delayed(Duration(seconds: 2), () {
// // if (mounted) {
// // setState(() {
// // _count += 20;
// // });
// // }
// // });
// },
// slivers: <Widget>[
// SliverAppBar(
// expandedHeight: 300.h,
// pinned: true,
// floating: true,
// backgroundColor: Colors.red,
// flexibleSpace: FlexibleSpaceBar(
// centerTitle: false,
// title: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// SlidingData([
// EntranceModel(
// title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath),
// EntranceModel(
// title: '学生历史作业',
// image: 'assets/images/job_home_history.png',
// navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history',
// ),
// EntranceModel(
// title: '知识点点掌握',
// image: 'assets/images/job_home_knowledge.png',
// navigationUrl: RouterManager.jobKnowledgePointsPath)
// ]),
// $TermRow([
// EntranceModel(
// title: '答题轨迹',
// image: 'assets/images/job_home_answer_record.png',
// navigationUrl: RouterManager.answerTrajectoryPath),
// EntranceModel(
// title: '优先批阅设定',
// image: 'assets/images/job_home_youxian.png',
// navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set',
// )
// ], 0),
// ],
// )),
// ),
// SliverList(
// delegate: SliverChildBuilderDelegate(
// (context, index) {
// return Container(
// height: 40.h,
// color: Colors.amber,
// width: ScreenUtil().screenWidth,
// );
// },
// childCount: 10,
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// ));
// }
// }
// class EntranceModel extends Object {
// String title;
// String image;
// String navigationUrl;
// EntranceModel({required this.title, required this.image, required this.navigationUrl});
// }
// class QuantityToBeReviewedData extends Object {
// int num;
// QuantityToBeReviewedData(this.num);
// }
// @swidget
// Widget $termRow(BuildContext context, List<EntranceModel> items, int data) {
// var leng = items.length;
// Widget childWidget;
// switch (leng) {
// case 1:
// childWidget = Row(children: [Expanded(child: $TermItem(items[0], data))]);
// break;
// case 2:
// childWidget = Row(children: [
// Expanded(flex: 9, child: $TermItem(items[0], data)),
// Expanded(flex: 1, child: SizedBox()),
// Expanded(flex: 9, child: $TermItem(items[1], data)),
// ]);
// break;
// case 3:
// double _theHeight = ScreenUtil().screenWidth / 19 + 54.h * 2;
// childWidget = Row(
// children: [
// Expanded(child: $TermItem(items[0], data, theHeight: _theHeight)),
// SizedBox(width: ScreenUtil().screenWidth / 19),
// Expanded(
// child: SizedBox(
// height: _theHeight,
// child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// $TermItem(items[1], data),
// $TermItem(items[2], data),
// ],
// ),
// ),
// ),
// ],
// );
// break;
// default:
// childWidget = Container();
// }
// return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget);
// }
// @swidget
// Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) {
// bool isJob = e.title == '作业批阅';
// return Material(
// color: Colors.white,
// elevation: 3.r,
// shadowColor: const Color.fromRGBO(231, 231, 231, 1),
// borderRadius: BorderRadius.all(Radius.circular(8.r)),
// child: InkWell(
// onTap: () => easyThrottle('GO_TO_JOB_HOME_NAVIGATION', () {
// RouterManager.router.navigateTo(context, e.navigationUrl, transition: getTransition());
// }),
// // splashColor: splashColor,
// borderRadius: BorderRadius.all(Radius.circular(8.r)),
// child: badges.Badge(
// showBadge: isJob && data > 0,
// ignorePointer: false,
// badgeContent: quickText(data, color: Colors.white, size: 10.sp),
// badgeAnimation: badges.BadgeAnimation.rotation(
// animationDuration: Duration(seconds: 1),
// colorChangeAnimationDuration: Duration(seconds: 1),
// loopAnimation: false,
// curve: Curves.fastOutSlowIn,
// colorChangeAnimationCurve: Curves.easeInCubic,
// ),
// badgeStyle: badges.BadgeStyle(
// badgeColor: Color.fromRGBO(255, 105, 105, 1),
// shape: badges.BadgeShape.square,
// borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)),
// // borderSide: BorderSide(color: Colors.white, width: 2),
// elevation: 1,
// padding: EdgeInsets.symmetric(horizontal: isPad() ? 11.w : 16.w, vertical: 2.h),
// ),
// position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r),
// child: Container(
// height: theHeight,
// padding: EdgeInsets.symmetric(vertical: 12.h),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.all(Radius.circular(8.r)),
// // boxShadow: [
// // BoxShadow(
// // color: const Color.fromRGBO(231, 231, 231, 1),
// // offset: Offset(4.w, 6.h), //y轴偏移量
// // blurRadius: 8, //
// // spreadRadius: 0.2, //
// // )
// // ],
// // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)),
// ),
// alignment: Alignment.center,
// child: isJob
// ? Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
// SizedBox(height: 6.r),
// quickText(e.title, size: 12.sp, color: Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
// ],
// )
// : Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
// SizedBox(width: 6.r),
// quickText(e.title, size: 12.sp, color: Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
// ],
// ),
// ),
// )),
// );
// }
// class SlidingData extends HookWidget with EventBusMixin {
// final List<EntranceModel> items;
// SlidingData(this.items);
// @override
// Widget build(BuildContext context) {
// var dataNumber = useState<QuantityToBeReviewedData?>(null);
// useEffect(() {
// eventOn(callback: (QuantityToBeReviewedData data) => (dataNumber.value = data));
// return () {
// eventCancel();
// };
// }, []);
// return $TermRow(items, dataNumber.value?.num ?? 0);
// }
// }
// ///
// class SecondFloorWidget extends StatefulWidget {
// // Header连接通知器
// final LinkHeaderNotifier linkNotifier;
// //
// final ValueNotifier<bool> secondFloorOpen;
// final Function refreshCall;
// const SecondFloorWidget(this.linkNotifier, this.secondFloorOpen, {required this.refreshCall, Key? key}) : super(key: key);
// @override
// State<StatefulWidget> createState() => SecondFloorWidgetState();
// }
// class SecondFloorWidgetState extends State<SecondFloorWidget> {
// //
// final double _openSecondFloorExtent = 100.0;
// //
// double? _indicatorValue = 0.0;
// //
// double _secondFloor = 0.0;
// //
// bool _toggleAnimation = false;
// Duration _toggleAnimationDuration = Duration(milliseconds: 300);
// //
// bool _isOpen = false;
// RefreshMode get _refreshState => widget.linkNotifier.refreshState;
// double get _pulledExtent => widget.linkNotifier.pulledExtent;
// @override
// void initState() {
// widget.linkNotifier.addListener(onLinkNotify);
// super.initState();
// }
// void onLinkNotify() {
// setState(() {
// if (_refreshState == RefreshMode.armed || _refreshState == RefreshMode.refresh) {
// _indicatorValue = null;
// //
// if (widget.secondFloorOpen.value && !_toggleAnimation) {
// _isOpen = true;
// _secondFloor = MediaQuery.of(context).size.height - 60.h;
// _toggleAnimation = true;
// Future.delayed(_toggleAnimationDuration, () {
// if (mounted) {
// setState(() {
// _toggleAnimation = false;
// });
// }
// });
// }
// } else if (_refreshState == RefreshMode.refreshed || _refreshState == RefreshMode.done) {
// _indicatorValue = 1.0;
// } else {
// if (_refreshState == RefreshMode.inactive) {
// _indicatorValue = 0.0;
// _toggleAnimation = true;
// Future.delayed(_toggleAnimationDuration, () {
// if (mounted) {
// setState(() {
// _toggleAnimation = false;
// });
// }
// });
// } else {
// double indicatorValue = _pulledExtent / 70.0 * 0.8;
// _indicatorValue = indicatorValue < 0.8 ? indicatorValue : 0.8;
// //
// if (_refreshState == RefreshMode.drag) {
// if (_pulledExtent >= _openSecondFloorExtent) {
// widget.secondFloorOpen.value = true;
// } else {
// widget.secondFloorOpen.value = false;
// }
// }
// }
// }
// });
// }
// @override
// Widget build(BuildContext context) {
// // var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19);
// // return RefreshIndicator(
// // onRefresh: () async => widget.refreshCall(),
// // child: ListView(
// // children: [
// // Container(
// // constraints: BoxConstraints(
// // minHeight: 200.h,
// // maxWidth: double.infinity,
// // ),
// // child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth),
// // ),
// // SizedBox(height: 30.h),
// // SlidingData([
// // EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath),
// // EntranceModel(
// // title: '学生历史作业',
// // image: 'assets/images/job_home_history.png',
// // navigationUrl: '${RouterManager.jobStudentGroupPath}?page=history',
// // ),
// // EntranceModel(title: '知识点点掌握', image: 'assets/images/job_home_knowledge.png', navigationUrl: RouterManager.jobKnowledgePointsPath)
// // ]),
// // spaceWidth,
// // $TermRow([
// // EntranceModel(title: '答题轨迹', image: 'assets/images/job_home_answer_record.png', navigationUrl: RouterManager.answerTrajectoryPath),
// // EntranceModel(
// // title: '优先批阅设定',
// // image: 'assets/images/job_home_youxian.png',
// // navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set',
// // )
// // ], 0),
// // // spaceWidth,
// // // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0),
// // ],
// // ),
// // );
// var heightVal = _isOpen
// ? _secondFloor
// : _refreshState == RefreshMode.inactive
// ? 0.0
// : _pulledExtent;
// return AnnotatedRegion(
// value: const SystemUiOverlayStyle(
// systemNavigationBarColor: Color(0xFF000000),
// systemNavigationBarDividerColor: null,
// statusBarColor: Colors.white,
// systemNavigationBarIconBrightness: Brightness.light,
// statusBarIconBrightness: Brightness.dark,
// statusBarBrightness: Brightness.light,
// ),
// child: InkWell(
// onTap: () {
// if (_isOpen) {
// setState(() {
// _isOpen = false;
// _toggleAnimation = true;
// Future.delayed(_toggleAnimationDuration, () {
// if (mounted) {
// setState(() {
// _toggleAnimation = false;
// });
// }
// });
// });
// }
// },
// child: AnimatedContainer(
// padding: EdgeInsets.zero,
// height: heightVal,
// color: Colors.white,
// duration: _toggleAnimation ? _toggleAnimationDuration : Duration(milliseconds: 1),
// child: Stack(
// children: <Widget>[
// Positioned(
// bottom: 0.0,
// left: 0.0,
// right: 0.0,
// child: Container(
// height: MediaQuery.of(context).size.height,
// width: double.infinity,
// child: Image.asset(
// 'assets/images/job_home_top_bgm.png',
// fit: BoxFit.fitHeight,
// ),
// ),
// ),
// Positioned(
// bottom: 0.0,
// left: 0.0,
// right: 0.0,
// child: AnimatedCrossFade(
// firstChild: Center(
// child: Container(
// alignment: Alignment.center,
// margin: EdgeInsets.only(
// bottom: 20.0,
// top: 10.0,
// ),
// width: 24.0,
// height: 24.0,
// child: Offstage(
// offstage: widget.secondFloorOpen.value,
// child: CircularProgressIndicator(
// value: _indicatorValue,
// valueColor: AlwaysStoppedAnimation(Colors.white),
// strokeWidth: 2.4,
// ),
// ),
// ),
// ),
// secondChild: Center(
// child: Container(
// alignment: Alignment.center,
// margin: EdgeInsets.only(
// bottom: 20.0,
// top: 10.0,
// ),
// child: Offstage(
// offstage: !widget.secondFloorOpen.value,
// child: Text(
// '欢迎来到二楼',
// style: TextStyle(fontSize: 18.0, color: Colors.white),
// ),
// ),
// ),
// ),
// crossFadeState: widget.secondFloorOpen.value ? CrossFadeState.showSecond : CrossFadeState.showFirst,
// duration: Duration(milliseconds: 300),
// ),
// ),
// ],
// ),
// ),
// ),
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:marking_app/common/mixin/common.dart';
import 'package:marking_app/common/model/common/base_page_data.dart';
import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart';
import 'package:marking_app/common/model/job/job_task_item.dart';
import 'package:marking_app/common/model/marking/marking_list_params.dart';
import 'package:marking_app/pages/common/event_bus_mixin.dart';
import 'package:marking_app/routes/RouterManager.dart';
import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart';
import 'package:marking_app/utils/easy_refresh/mixin/refresh_data_handle.dart';
import 'package:marking_app/utils/index.dart';
import 'package:marking_app/utils/my_text.dart';
import 'package:badges/badges.dart' as badges;
import 'package:marking_app/utils/request/rest_client.dart';
import '../../utils/my_future_builder.dart';
import 'components/new_version_of_homework/homework_tasks_view_item.dart';
part 'job_home.g.dart';
@ -24,37 +573,51 @@ class JobHome extends StatefulWidget {
State<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
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
void initState() {
getData();
eventOn(callback: (JobHomeRefreshBus item) => getData());
_refreshController = EasyRefreshController();
super.initState();
}
@override
void dispose() {
_refreshController.dispose();
eventCancel();
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;
/* 发起请求 => 作业 */
Future<void> toGetPageData({bool isReFresh = false}) async {
if (!isReFresh) {
param.page++;
}
RestClient client = await getClient();
BasePageData<JobTaskItem>? results = await toRefreshData(
_refreshController,
api: client.getJobsByPage,
params: param,
isReFresh: isReFresh,
context: context,
);
if (results != null) {
Future.delayed(Duration(seconds: 1), () => eventFire(model: QuantityToBeReviewedData(results.total)));
if (isReFresh) {
jobDatas.clear();
jobDatas = results.items;
} else
jobDatas.addAll(results.items);
setState(() {});
}
}
@ -71,24 +634,31 @@ class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, Auto
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
),
child: RefreshIndicator(
onRefresh: () async => eventFire(model: JobHomeRefreshBus()),
child: EasyRefresh(
firstRefresh: true,
taskIndependence: true,
enableControlFinishLoad: true,
enableControlFinishRefresh: true,
emptyWidget: jobDatas.isEmpty ? const MyEmptyWidget() : null,
controller: _refreshController,
header: MaterialHeader(),
footer: TaurusFooter(),
child: ListView(
children: [
Container(
constraints: BoxConstraints(
minHeight: 200.h,
maxWidth: double.infinity,
),
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage('assets/images/job_home_top_bgm.png'),
// fit: BoxFit.fitWidth, //
// ),
// ),
child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth),
),
SizedBox(height: 30.h),
// Container(
// constraints: BoxConstraints(
// minHeight: 200.h,
// maxWidth: double.infinity,
// ),
// // decoration: BoxDecoration(
// // image: DecorationImage(
// // image: AssetImage('assets/images/job_home_top_bgm.png'),
// // fit: BoxFit.fitWidth, //
// // ),
// // ),
// child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth),
// ),
SizedBox(height: MediaQuery.of(context).padding.top + 20.h),
SlidingData([
EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: RouterManager.jobMainListPagePath),
EntranceModel(
@ -109,8 +679,19 @@ class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, Auto
], 0),
// spaceWidth,
// $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0),
spaceWidth,
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: Column(
children: jobDatas
.map((e) => HomeworkTasksViewItem(completed: false, jobTaskItem: e, call: () => _refreshController.callRefresh()))
.toList(),
),
)
],
),
onRefresh: () => toGetPageData(isReFresh: true),
onLoad: () => toGetPageData(isReFresh: false),
),
);
}

View File

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

View File

@ -375,19 +375,35 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
late ImageStreamListener theImageStreamListener;
late ValueNotifier<List<GestureHandwritingRecording>> _vnHandWritings;
late ValueNotifier<List<GestureHandwritingRecording>> _vnPrimaryHandWritings;
late RemoveListener _jobHandwritingDrawingTrajectoryListener; //
late RemoveListener _jobHandwritingDrawingTrajectoryListener1; // 稿
List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
List<GestureHandwritingRecording> _packagedHandwritingDataAll = [];
List<GestureHandwritingRecording> _packagedHandwritingDataAll = []; //
List<GestureHandwritingRecording> pendingData = []; //
List<Timer> timers = [];
int handwritingTime = 0;
int handwritingDuration = 0;
double speed = 1; //
double speed = 2.0; //
@override
void initState() {
super.initState();
_vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
_jobHandwritingDrawingTrajectoryListener1 = ref.read(jobHandwritingStudentManuscriptProvider.notifier).addListener((state) {
print('点击进入了');
// 稿
if (state.showManuscript) {
// 稿
eventFire(model: JobHandwritingPlaybarBus(false)); //
_vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll];
} else {
// 稿
_vnPrimaryHandWritings.value = [];
}
}, fireImmediately: false);
_jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) {
_vnHandWritings.value = state;
}, fireImmediately: false);
@ -447,7 +463,9 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
if (e.isActive) e.cancel();
});
_jobHandwritingDrawingTrajectoryListener();
_jobHandwritingDrawingTrajectoryListener1();
_vnHandWritings.dispose();
_vnPrimaryHandWritings.dispose();
try {
imageStream?.removeListener(theImageStreamListener);
eventCancel();
@ -537,7 +555,7 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
pendingData.addAll(_packagedHandwritingDataAll);
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
}
ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(false));
executableData.forEach((e) {
var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e));
timers.add(ter);
@ -579,14 +597,12 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
@override
Widget build(BuildContext context) {
var showManuscript = ref.watch(jobHandwritingStudentManuscriptProvider).showManuscript;
return Container(
alignment: Alignment.center,
child: RepaintBoundary(
child: CustomPaint(
willChange: true,
isComplex: true,
foregroundPainter: HandWritingDrawingPainter(ctrl: _vnHandWritings),
// size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight),
foregroundPainter: HandWritingDrawingPainter(ctrl: showManuscript ? _vnPrimaryHandWritings : _vnHandWritings),
child: RepaintBoundary(
child: $TheCachedNetworkImage(
imageUrl: widget.image,
@ -609,6 +625,47 @@ class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with Ev
}
}
class HandWritingDrawingPainter1 extends CustomPainter {
final ValueNotifier<List<GestureHandwritingRecording>> ctrl;
HandWritingDrawingPainter1({required this.ctrl}) : super(repaint: ctrl);
//[]
final Paint paintBrush = Paint()
//
..color = Colors.black
//
..strokeCap = StrokeCap.round
//齿
..isAntiAlias = true
//
// ..style = PaintingStyle.fill
//
..style = PaintingStyle.stroke
..strokeWidth = 0.5.r;
@override
void paint(Canvas canvas, Size size) {
// canvas.drawPoints(PointMode.points, thePoints, paintBrush);
var points = ctrl.value;
var _length = points.length;
for (int i = 0; i < _length; i++) {
GestureHandwritingRecording item = points[i];
GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null;
Offset offsetData = item.data;
Offset? nextOffsetData = nextItem?.data;
if (nextOffsetData != null && item.stroke == nextItem?.stroke) {
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false; // oldDelegate MyCustomPainter
}
}
class HandWritingDrawingPainter extends CustomPainter {
final ValueNotifier<List<GestureHandwritingRecording>> ctrl;
HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl);
@ -746,148 +803,174 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L
}, []);
return Container(
height: 60.h,
height: 62.h,
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
alignment: Alignment.center,
color: Color.fromRGBO(0, 0, 0, 0.4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (usePlaybar.handWritingReady.value)
InkWell(
onTap: () => easyThrottle('job_handwriting_play_pause', () {
if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹');
Container(alignment: Alignment.centerRight, child: StudentManuscriptBtn()), // 稿
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (usePlaybar.handWritingReady.value)
InkWell(
onTap: () => easyThrottle('job_handwriting_play_pause', () {
if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹');
usePlaybar.playPause.value = !usePlaybar.playPause.value;
usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
}),
child: Icon(
!usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
color: Colors.white,
size: 28.r,
),
)
else
SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white),
SizedBox(width: 6.w),
Expanded(
child: LayoutBuilder(builder: (context, constraints) {
final double containerWidth = constraints.maxWidth; //
var unitScale = containerWidth / timeConsuming; //
var pauseIntervalsLength = pauseIntervals.length;
List<Widget> pauseTickMarks = pauseIntervals.asMap().keys.map((e) {
bool isLast = e == pauseIntervalsLength - 1;
bool isFirst = e == 0;
var item = pauseIntervals[e];
return Positioned(
top: 0,
left: unitScale * item.startTime,
child: Container(
width: unitScale * (item.apart ?? 0),
height: 8.h,
decoration: BoxDecoration(
color: Color.fromRGBO(202, 201, 201, 1),
borderRadius: isFirst
? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r))
: (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null),
),
usePlaybar.playPause.value = !usePlaybar.playPause.value;
usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
}),
child: Icon(
!usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
color: Colors.white,
size: 28.r,
),
);
}).toList();
)
else
SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white),
SizedBox(width: 6.w),
Expanded(
child: LayoutBuilder(builder: (context, constraints) {
final double containerWidth = constraints.maxWidth; //
var unitScale = containerWidth / timeConsuming; //
var pauseIntervalsLength = pauseIntervals.length;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Stack(
children: [
Container(
List<Widget> pauseTickMarks = pauseIntervals.asMap().keys.map((e) {
bool isLast = e == pauseIntervalsLength - 1;
bool isFirst = e == 0;
var item = pauseIntervals[e];
return Positioned(
top: 0,
left: unitScale * item.startTime,
child: Container(
width: unitScale * (item.apart ?? 0),
height: 8.h,
width: containerWidth,
decoration: BoxDecoration(
// color: Color.fromRGBO(146, 146, 146, 1),
color: Colors.white,
borderRadius: BorderRadius.circular(50.r),
color: Color.fromRGBO(202, 201, 201, 1),
borderRadius: isFirst
? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r))
: (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null),
),
),
...pauseTickMarks,
Container(
height: 8.h,
);
}).toList();
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Stack(
children: [
Container(
height: 8.h,
width: containerWidth,
decoration: BoxDecoration(
// color: Color.fromRGBO(146, 146, 146, 1),
color: Colors.white,
borderRadius: BorderRadius.circular(50.r),
),
),
...pauseTickMarks,
Container(
height: 8.h,
width: containerWidth,
// color: Theme.of(context).primaryColor,
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 8.h, //
trackShape: RoundedRectSliderTrackShape(), //
activeTrackColor: Theme.of(context).primaryColor, //
inactiveTrackColor: Colors.transparent, //
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0),
thumbColor: Colors.white, //
overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
overlayColor: Colors.black54, //
// valueIndicatorShape: PaddleSliderValueIndicatorShape(), //
),
child: Slider(
value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(),
min: 0.0,
max: usePlaybar.handwritingDuration.value.toDouble(),
inactiveColor: Colors.transparent,
onChangeEnd: (value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.playTimingSuspend(); //
usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value));
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
},
onChanged: (double value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
},
),
),
),
],
),
SizedBox(height: 4.h),
SizedBox(
width: containerWidth,
// color: Theme.of(context).primaryColor,
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 8.h, //
trackShape: RoundedRectSliderTrackShape(), //
activeTrackColor: Theme.of(context).primaryColor, //
inactiveTrackColor: Colors.transparent, //
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0),
thumbColor: Colors.white, //
overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
overlayColor: Colors.black54, //
// valueIndicatorShape: PaddleSliderValueIndicatorShape(), //
),
child: Slider(
value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(),
min: 0.0,
max: usePlaybar.handwritingDuration.value.toDouble(),
inactiveColor: Colors.transparent,
onChangeEnd: (value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.playTimingSuspend(); //
usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value));
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
},
onChanged: (double value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
},
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp),
quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp),
],
),
),
)
],
),
SizedBox(height: 4.h),
SizedBox(
width: containerWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp),
quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp),
],
),
)
],
);
}),
),
SizedBox(width: 16.w),
InkWell(
onTap: () => easyThrottle('job_handwriting_speed', () {
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
if (theIndex == PlaybackSpeed.values.length - 1) {
theIndex = -1;
}
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
}, duration: Duration(milliseconds: 500)),
child: Container(
// alignment: Alignment.,
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
child: quickText(
'${usePlaybar.constantFastSpeed.value.name}',
color: Color.fromRGBO(79, 114, 244, 1),
size: 8.sp,
align: TextAlign.center,
);
}),
),
),
),
SizedBox(width: 16.w),
InkWell(
onTap: () => easyThrottle('job_handwriting_speed', () {
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
if (theIndex == PlaybackSpeed.values.length - 1) {
theIndex = -1;
}
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
}, duration: Duration(milliseconds: 500)),
child: Container(
// alignment: Alignment.,
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
child: quickText(
'${usePlaybar.constantFastSpeed.value.name}',
color: Color.fromRGBO(79, 114, 244, 1),
size: 8.sp,
align: TextAlign.center,
),
),
),
],
)
],
),
);
}
// 稿
class StudentManuscriptBtn extends ConsumerWidget {
const StudentManuscriptBtn({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return InkWell(
onTap: () => easyThrottle('job_handwriting_udent_manuscript', () {
var showManuscript = ref.read(jobHandwritingStudentManuscriptProvider).showManuscript;
ref.read(jobHandwritingStudentManuscriptProvider.notifier).setVal(ShowStudentMmanuscript(!showManuscript));
}),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 1.h),
decoration: BoxDecoration(color: Colors.grey, borderRadius: BorderRadius.circular(4.r)),
child: quickText('学生原稿', color: Colors.white, size: 8.sp),
),
);
}
}
class SysjTime extends StatefulWidget {
const SysjTime({super.key});
@ -921,7 +1004,7 @@ class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRu
class UseBottomPlaybar with EventBusMixin {
final ValueNotifier<int> handwritingDuration; //
final ValueNotifier<bool> playPause; //
final ValueNotifier<PlaybackSpeed> constantFastSpeed; //
final ValueNotifier<PlaybackSpeed> constantFastSpeed; //
final ValueNotifier<bool> handWritingReady;
final ValueNotifier<int> useTime; //
@ -942,7 +1025,7 @@ class UseBottomPlaybar with EventBusMixin {
if ((milliseconds % 1000) > 500) handwritingDuration += 1;
return UseBottomPlaybar._(
playPause: useState(false),
constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED),
constantFastSpeed: useState(PlaybackSpeed.DOUBLE_SPEED), //
useTime: useState(handwritingDuration),
timer: useState(null),
handwritingDuration: useState(handwritingDuration),