966 lines
38 KiB
Dart
966 lines
38 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.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/marking/do_marking_keyboard_model.dart';
|
||
import 'package:marking_app/common/model/marking/keyboard_assist_event.dart';
|
||
import 'package:marking_app/common/model/marking/marking_common_score_items.dart';
|
||
import 'package:marking_app/common/model/marking/marking_keyboard_sliding_position.dart';
|
||
import 'package:marking_app/common/model/marking/marking_text_question.dart';
|
||
import 'package:marking_app/pages/common/event_bus_mixin.dart';
|
||
import 'package:marking_app/provider/do_marking_provider.dart';
|
||
import 'package:marking_app/utils/index.dart';
|
||
import 'package:marking_app/utils/marking_utils/index.dart';
|
||
import 'package:marking_app/utils/my_text.dart';
|
||
|
||
// 选择型键盘
|
||
|
||
class SelectableKeyboard extends StatefulHookConsumerWidget {
|
||
int markingUserId;
|
||
MarkingTextQuestion data;
|
||
String questScore; // 当前分值
|
||
double totalScore; // 总分
|
||
bool hasSubtopic = false; // 是否有小题
|
||
int subtopicIndex; // 小题下标
|
||
SynchroScoreCallback synchroScore;
|
||
GestureTapCallback submitCall;
|
||
SelectableKeyboard({
|
||
required this.data,
|
||
required this.markingUserId,
|
||
required this.questScore,
|
||
required this.totalScore,
|
||
required this.synchroScore,
|
||
required this.subtopicIndex,
|
||
required this.submitCall,
|
||
Key? key,
|
||
}) : hasSubtopic = data.subQuestionDetailList.isNotEmpty,
|
||
super(key: key);
|
||
|
||
@override
|
||
_SelectableKeyboardState createState() => _SelectableKeyboardState();
|
||
}
|
||
|
||
class _SelectableKeyboardState extends ConsumerState<SelectableKeyboard>
|
||
with SingleTickerProviderStateMixin, EventBusMixin<KeyboardAssistEvent> {
|
||
late ScrollController _scrollController;
|
||
late AnimationController _animationController;
|
||
|
||
bool isRight = true; // 是否是右侧打分键盘
|
||
String? _smallScore; // 小题打分
|
||
|
||
late List nums; // 打开辅助键盘的个位数集合
|
||
late List tens = []; // 十位数集合
|
||
List subNums = []; // 关闭辅助键盘后的小键盘
|
||
late RemoveListener _markingKeyboardListener;
|
||
late RemoveListener _markingSubtopicSwitchingListener;
|
||
late bool _openAuxiliary;
|
||
num? _tensVal; // 当前选中十位分值
|
||
late Duration easyThrottleTime;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
// 初始化不执行
|
||
easyThrottleTime = Duration(milliseconds: widget.hasSubtopic ? 400 : 800);
|
||
_scrollController = ScrollController()..addListener(scrollListener);
|
||
|
||
/// 小题切换监听,重置键盘
|
||
_markingSubtopicSwitchingListener = ref.read(markingSubtopicSwitchingProvider.notifier).addListener((state) {
|
||
if (widget.subtopicIndex != state) widget.subtopicIndex = state;
|
||
|
||
DoMarkingKeyboardModel preference = ref.read(markingKeyboardProvider);
|
||
initKeyboardSuper(
|
||
preference.getScoreStepSize(widget.markingUserId, widget.data.questionNum, widget.data.scoreInterval),
|
||
preference.sort!);
|
||
toUp();
|
||
}, fireImmediately: false);
|
||
|
||
_markingKeyboardListener = ref.read(markingKeyboardProvider.notifier).addListener((state) {
|
||
isRight = state.keyboard == KeyboardType.RIGHT_SELECTION;
|
||
if (state.sort == null) return;
|
||
initKeyboardSuper(
|
||
state.getScoreStepSize(widget.markingUserId, widget.data.questionNum, widget.data.scoreInterval),
|
||
state.sort!);
|
||
toUp();
|
||
});
|
||
_openAuxiliary = ref.read(markingKeyboardProvider).openAuxiliary;
|
||
_animationController = AnimationController(
|
||
value: _openAuxiliary ? 144 : 72, // 设置默认值
|
||
duration: const Duration(milliseconds: 400),
|
||
lowerBound: 72,
|
||
upperBound: 144,
|
||
vsync: this,
|
||
)..addListener(toUp);
|
||
|
||
// 事件总线监听
|
||
eventOn(callback: (KeyboardAssistEvent item) {
|
||
bool openAuxiliary = item.openAuxiliary;
|
||
if (!openAuxiliary && _tensVal != null) {
|
||
// 关闭辅助键盘并且清空当前打分的分值
|
||
marking(fraction: _tensVal!, isTens: true);
|
||
}
|
||
openAuxiliary ? _animationController.forward() : _animationController.reverse();
|
||
ref.read(markingKeyboardProvider.notifier).changeOpenAuxiliary(openAuxiliary).then((value) {
|
||
if (value != null) _openAuxiliary = value;
|
||
});
|
||
});
|
||
}
|
||
|
||
void toUp() {
|
||
toUpState(setState, () {}, mounted);
|
||
}
|
||
|
||
/** 键盘滚动位置监听 */
|
||
void scrollListener() {
|
||
// 保存当前滑动位置,这里假设使用SharedPreferences存储位置为"scroll_position" data
|
||
FastData.getInstance().setMarkingKeyboardSlidingPosition(MarkingKeyboardSlidingPosition(
|
||
id: widget.markingUserId,
|
||
questionNum: widget.data.questionNum,
|
||
position: _scrollController.position.pixels,
|
||
));
|
||
}
|
||
|
||
@override
|
||
void didChangeDependencies() {
|
||
super.didChangeDependencies();
|
||
// 获取历史滑动位置,这里假设使用SharedPreferences存储位置为"scroll_position"
|
||
FastData.getInstance().getMarkingKeyboardSlidingPosition().then((historyPosition) {
|
||
// 检查是否有历史滑动位置并且ListView已经完成渲染
|
||
bool flag = historyPosition != null &&
|
||
!historyPosition.isVertical &&
|
||
historyPosition.position >= 0 &&
|
||
_scrollController.hasClients &&
|
||
historyPosition.questionNum == widget.data.questionNum &&
|
||
historyPosition.id == widget.markingUserId;
|
||
if (flag) {
|
||
// 使用JumpTo或AnimateTo方法滚动到历史位置
|
||
_scrollController.jumpTo(historyPosition.position);
|
||
// _scrollController.animateTo(
|
||
// historyPosition.position,
|
||
// duration: Duration(milliseconds: 350),
|
||
// curve: Curves.easeInOut,
|
||
// );
|
||
}
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
super.dispose();
|
||
|
||
_scrollController
|
||
..removeListener(scrollListener)
|
||
..dispose();
|
||
_markingKeyboardListener();
|
||
_markingSubtopicSwitchingListener();
|
||
_animationController
|
||
..removeListener(toUp)
|
||
..dispose();
|
||
eventCancel();
|
||
}
|
||
|
||
/// 键盘计算数据
|
||
/// @params localScoreInterval 本地设置分值步长
|
||
/// @params sort 键盘排序方式
|
||
void initKeyboardSuper(double? localScoreInterval, SortKeyboard sort) {
|
||
double scoreInterval = widget.data.scoreInterval; // 服务器针对当前实体设置的分值步长
|
||
if (localScoreInterval != null && localScoreInterval != 0 && localScoreInterval != scoreInterval) {
|
||
scoreInterval = localScoreInterval;
|
||
}
|
||
double totalScore = widget.hasSubtopic
|
||
? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
: widget.totalScore;
|
||
|
||
if (scoreInterval == 0) scoreInterval = 1;
|
||
initKeyboard(totalScore, scoreInterval, sort);
|
||
}
|
||
|
||
/// 初始化键盘
|
||
/// @params {double} totalScore 总分
|
||
/// @params {double} scoreInterval 小分步长
|
||
void initKeyboard(double totalScore, double scoreInterval, SortKeyboard sort) {
|
||
tens.clear();
|
||
int floorScore = totalScore.floor(); // 总分向下取整
|
||
int singleDigit = floorScore; // 个位小数
|
||
int numsLength = singleDigit;
|
||
if (floorScore > 10) {
|
||
singleDigit = 9;
|
||
for (var i = 10; i < floorScore; i += 10) {
|
||
tens.add(i);
|
||
}
|
||
}
|
||
numsLength = ((numsLength - (numsLength % scoreInterval)) / scoreInterval).floor();
|
||
|
||
/// +1 添加满分
|
||
subNums = List.generate(numsLength + 1, (e) => e * scoreInterval); // 小分键盘
|
||
|
||
// 加一个总分
|
||
if (numsLength * scoreInterval < totalScore) subNums.add(totalScore);
|
||
nums = jsonDecode(jsonEncode(subNums)); // 辅助键盘的小分键盘
|
||
if (sort != SortKeyboard.FULL_AND_AERO_TOP) {
|
||
if (totalScore > 19) {
|
||
nums = nums.reversed.toList();
|
||
} else {
|
||
nums = nums.reversed.where((e) => e <= 10).toList();
|
||
}
|
||
subNums = subNums.reversed.toList();
|
||
}
|
||
|
||
// // 计算关闭辅助键盘后的小键盘
|
||
// if (floorScore > 10) {
|
||
// int a = scoreInterval == 0.5 ? floorScore * 2 : floorScore;
|
||
// subNums = List.generate(a+1, (e) => e * scoreInterval); // 小分键盘
|
||
// }
|
||
}
|
||
|
||
/// 打分
|
||
/// @params {num} fraction 分数
|
||
/// @params {bool} isTens 十位分数
|
||
/// @params {bool} fullScore 满分
|
||
Future<void> marking({required num fraction, String? strScore, bool isTens = false, bool fullScore = false}) async {
|
||
// 零分的处理
|
||
bool allWrong = fraction == 0 && fullScore;
|
||
if (allWrong) {
|
||
fullScore = false;
|
||
}
|
||
|
||
// 十位
|
||
if (!fullScore && isTens) {
|
||
bool cleanScore = _tensVal == fraction;
|
||
if (!cleanScore) {
|
||
_tensVal = fraction;
|
||
} else {
|
||
_tensVal = null;
|
||
toUpState(setState, () => _smallScore = null, mounted);
|
||
}
|
||
return await widget.synchroScore(
|
||
score: fraction.toDouble(),
|
||
continueScoring: true,
|
||
hasSubtopic: widget.hasSubtopic,
|
||
cleanScore: cleanScore,
|
||
);
|
||
}
|
||
|
||
toUpState(setState, () => _smallScore = strScore, mounted);
|
||
EasyLoading.show(status: 'loading...');
|
||
try {
|
||
double theScore = fraction.toDouble();
|
||
if (fullScore) {
|
||
// 满分
|
||
theScore = widget.data.totalScore;
|
||
/** 小题单个分值
|
||
theScore = widget.hasSubtopic
|
||
? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
: fraction.toDouble(); */
|
||
} else if (_tensVal != null) {
|
||
// 有十位数
|
||
theScore = (_tensVal! + fraction).toDouble();
|
||
}
|
||
|
||
if (theScore > widget.totalScore) {
|
||
return ToastUtils.showInfo('评分已大于总分,请重新评分');
|
||
}
|
||
|
||
await widget
|
||
.synchroScore(
|
||
score: theScore,
|
||
continueScoring: false,
|
||
allWrong: allWrong,
|
||
hasSubtopic: widget.hasSubtopic,
|
||
)
|
||
.then((_) {
|
||
if (widget.hasSubtopic) {
|
||
// 是否有小题
|
||
List<SubQuestions> subQuestionDetailList = widget.data.subQuestionDetailList;
|
||
|
||
if (subQuestionDetailList.map((e) => e.completeRating).contains(false)) {
|
||
setTimeOut(100, () => toUpState(setState, () => _smallScore = null, mounted));
|
||
return;
|
||
}
|
||
}
|
||
widget.submitCall(); // 提交
|
||
});
|
||
} catch (e) {
|
||
toPrint(val: e.toString());
|
||
} finally {
|
||
EasyLoading.dismiss();
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
DoMarkingKeyboardModel thePreference = ref.watch(markingKeyboardProvider);
|
||
bool henping = thePreference.screenDirection == ScreenDirection.HORIZONTAL_SCREEN; // 屏幕方向
|
||
MarkingCommonScoreItems? commonScores = thePreference.commonScores;
|
||
List<double> theCommonScores = [];
|
||
if (commonScores != null &&
|
||
commonScores.questionNum == widget.data.questionNum &&
|
||
commonScores.id == widget.markingUserId) {
|
||
theCommonScores = commonScores.score;
|
||
}
|
||
SortKeyboard sort = thePreference.sort!;
|
||
|
||
if (!isRight) {
|
||
return Container();
|
||
}
|
||
// 当前试题有无小题,有小题就是当前小题的总分,无小题就是当前试题的总分
|
||
double newTotalScore = widget.hasSubtopic
|
||
? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
: widget.totalScore;
|
||
|
||
// 已经选中辅助键盘的分数,扣除十位分数剩余分数差值
|
||
double dValue = _tensVal != null ? newTotalScore - _tensVal!.toDouble() : newTotalScore; // 差值
|
||
|
||
double animationVal = _animationController.value.h;
|
||
|
||
List<double> miniKeyboard = [...theCommonScores, ...(!_openAuxiliary && newTotalScore > 10 ? subNums : nums)];
|
||
int theCommonScoresLength = theCommonScores.length;
|
||
// 右侧键盘
|
||
return Container(
|
||
width: henping ? animationVal : animationVal - 16.h,
|
||
// width: animationVal,
|
||
margin: EdgeInsets.only(top: 0.6.w),
|
||
child: Row(
|
||
children: [
|
||
// 辅助栏
|
||
SizedBox(
|
||
width: animationVal - (henping ? 72.h : 72.h),
|
||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||
Ink(
|
||
color: const Color.fromRGBO(249, 250, 254, 1),
|
||
child: InkWell(
|
||
splashColor: Colors.cyanAccent,
|
||
onTap: () {
|
||
easyThrottle('toMarkingVal', () => marking(fraction: 0, fullScore: true, strScore: '0'),
|
||
duration: easyThrottleTime);
|
||
},
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 56.h,
|
||
margin: EdgeInsets.only(top: 3.h),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
border: Border.all(
|
||
width: 1.h,
|
||
color: Color.fromARGB(255, 189, 195, 216),
|
||
),
|
||
borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
),
|
||
child: quickText(widget.hasSubtopic ? '全错' : '零分',
|
||
size: 15.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
||
),
|
||
),
|
||
),
|
||
GestureDetector(
|
||
onTap: () {
|
||
easyThrottle('toMarkingVal', () => marking(fraction: widget.totalScore, fullScore: true),
|
||
duration: easyThrottleTime);
|
||
},
|
||
child: Container(
|
||
height: 58.h,
|
||
margin: EdgeInsets.only(top: 1.w),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: const Color.fromRGBO(4, 201, 208, 1),
|
||
borderRadius: BorderRadius.all(Radius.circular(1.w)),
|
||
),
|
||
child: quickText(
|
||
widget.hasSubtopic ? '全对' : '满分',
|
||
size: 17.sp,
|
||
fontWeight: FontWeight.w400,
|
||
color: const Color.fromRGBO(255, 255, 255, 1),
|
||
),
|
||
),
|
||
),
|
||
...tens.map((e) {
|
||
return InkWell(
|
||
onTap: () {
|
||
easyThrottle('toMarkingVal', () => marking(fraction: e, isTens: true), duration: easyThrottleTime);
|
||
},
|
||
child: Container(
|
||
height: 58.h,
|
||
margin: EdgeInsets.only(top: 1.w),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: _tensVal == e ? Colors.amber[800] : Theme.of(context).primaryColor,
|
||
borderRadius: BorderRadius.all(Radius.circular(1.w)),
|
||
),
|
||
child: quickText(
|
||
'$e+',
|
||
size: 17.sp,
|
||
fontWeight: FontWeight.w500,
|
||
color: const Color.fromRGBO(255, 255, 255, 1),
|
||
),
|
||
),
|
||
);
|
||
}).toList()
|
||
]),
|
||
),
|
||
// 小分栏
|
||
Expanded(
|
||
child: Container(
|
||
width: henping ? 72.h : 60.h,
|
||
// width: 72.h,
|
||
padding: EdgeInsets.symmetric(horizontal: 4.h, vertical: 4.h),
|
||
decoration: BoxDecoration(
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: const Color.fromRGBO(46, 91, 255, 0.2),
|
||
offset: Offset(0, 8.w), //阴影y轴偏移量
|
||
blurRadius: 1, //阴影模糊程度
|
||
spreadRadius: 2, //阴影扩散程度
|
||
)
|
||
],
|
||
color: const Color.fromRGBO(255, 255, 255, 1),
|
||
),
|
||
child: ListView(
|
||
controller: _scrollController,
|
||
children: miniKeyboard.asMap().keys.map((i) {
|
||
bool isCommonScoring = theCommonScores.isNotEmpty && i <= theCommonScoresLength - 1;
|
||
|
||
double e = miniKeyboard[i];
|
||
String strScore = getDoubleRemoveZero(e);
|
||
bool isCurrentSelect = _smallScore == strScore; // 当前选中
|
||
|
||
if (e == 0 && SortKeyboard.FULL_AND_AERO_TOP_INVERTED_ORDER == sort) {
|
||
return Container();
|
||
}
|
||
bool effective = e <= dValue;
|
||
return Ink(
|
||
child: InkWell(
|
||
splashColor: Colors.cyanAccent,
|
||
onTap: effective
|
||
? () => easyThrottle('toMarkingVal', () => marking(fraction: e, strScore: strScore),
|
||
duration: easyThrottleTime)
|
||
: null,
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 56.h,
|
||
margin: EdgeInsets.only(top: 3.h),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
border: Border.all(
|
||
width: 1.h,
|
||
color: const Color.fromRGBO(224, 230, 255, 1),
|
||
),
|
||
color: isCurrentSelect
|
||
? Theme.of(context).primaryColor
|
||
: effective
|
||
? const Color.fromRGBO(249, 250, 254, 1)
|
||
: Colors.grey[300],
|
||
borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
),
|
||
child: quickText(
|
||
strScore,
|
||
size: 15.sp,
|
||
color: isCurrentSelect ? Colors.white : const Color.fromRGBO(148, 163, 182, 1),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}).toList(),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// class SelectableKeyboard extends StatefulHookConsumerWidget {
|
||
// int markingUserId;
|
||
// MarkingTextQuestion data;
|
||
// String questScore; // 当前分值
|
||
// double totalScore; // 总分
|
||
// bool hasSubtopic = false; // 是否有小题
|
||
// int subtopicIndex; // 小题下标
|
||
// SynchroScoreCallback synchroScore;
|
||
// GestureTapCallback submitCall;
|
||
// SelectableKeyboard({
|
||
// required this.data,
|
||
// required this.markingUserId,
|
||
// required this.questScore,
|
||
// required this.totalScore,
|
||
// required this.synchroScore,
|
||
// required this.subtopicIndex,
|
||
// required this.submitCall,
|
||
// Key? key,
|
||
// }) : hasSubtopic = data.subQuestionDetailList.isNotEmpty,
|
||
// super(key: key);
|
||
|
||
// @override
|
||
// _SelectableKeyboardState createState() => _SelectableKeyboardState();
|
||
// }
|
||
|
||
// class _SelectableKeyboardState extends ConsumerState<SelectableKeyboard>
|
||
// with SingleTickerProviderStateMixin, EventBusMixin<KeyboardAssistEvent> {
|
||
// late ScrollController _scrollController;
|
||
// late AnimationController _animationController;
|
||
|
||
// bool isRight = true; // 是否是右侧打分键盘
|
||
// String? _smallScore; // 小题打分
|
||
|
||
// late List nums; // 打开辅助键盘的个位数集合
|
||
// late List tens = []; // 十位数集合
|
||
// List subNums = []; // 关闭辅助键盘后的小键盘
|
||
// late RemoveListener _markingKeyboardListener;
|
||
// late RemoveListener _markingSubtopicSwitchingListener;
|
||
// late bool _openAuxiliary;
|
||
// num? _tensVal; // 当前选中十位分值
|
||
// final Duration easyThrottleTime = Duration(seconds: 1);
|
||
|
||
// @override
|
||
// void initState() {
|
||
// super.initState();
|
||
// // 初始化不执行
|
||
|
||
// _scrollController = ScrollController()..addListener(scrollListener);
|
||
|
||
// /// 小题切换监听,重置键盘
|
||
// _markingSubtopicSwitchingListener = ref.read(markingSubtopicSwitchingProvider.notifier).addListener((state) {
|
||
// if (widget.subtopicIndex != state) widget.subtopicIndex = state;
|
||
|
||
// DoMarkingKeyboardModel preference = ref.read(markingKeyboardProvider);
|
||
// initKeyboardSuper(
|
||
// preference.getScoreStepSize(widget.markingUserId, widget.data.questionNum, widget.data.scoreInterval),
|
||
// preference.sort!);
|
||
// toUp();
|
||
// }, fireImmediately: false);
|
||
|
||
// _markingKeyboardListener = ref.read(markingKeyboardProvider.notifier).addListener((state) {
|
||
// isRight = state.keyboard == KeyboardType.RIGHT_SELECTION;
|
||
// if (state.sort == null) return;
|
||
// initKeyboardSuper(
|
||
// state.getScoreStepSize(widget.markingUserId, widget.data.questionNum, widget.data.scoreInterval),
|
||
// state.sort!);
|
||
// toUp();
|
||
// });
|
||
// _openAuxiliary = ref.read(markingKeyboardProvider).openAuxiliary;
|
||
// _animationController = AnimationController(
|
||
// value: _openAuxiliary ? 144 : 72, // 设置默认值
|
||
// duration: const Duration(milliseconds: 400),
|
||
// lowerBound: 72,
|
||
// upperBound: 144,
|
||
// vsync: this,
|
||
// )..addListener(toUp);
|
||
|
||
// // 事件总线监听
|
||
// eventOn(callback: (KeyboardAssistEvent item) {
|
||
// bool openAuxiliary = item.openAuxiliary;
|
||
// if (!openAuxiliary && _tensVal != null) {
|
||
// // 关闭辅助键盘并且清空当前打分的分值
|
||
// marking(fraction: _tensVal!, isTens: true);
|
||
// }
|
||
// openAuxiliary ? _animationController.forward() : _animationController.reverse();
|
||
// ref.read(markingKeyboardProvider.notifier).changeOpenAuxiliary(openAuxiliary).then((value) {
|
||
// if (value != null) _openAuxiliary = value;
|
||
// });
|
||
// });
|
||
// }
|
||
|
||
// void toUp() {
|
||
// toUpState(setState, () {}, mounted);
|
||
// }
|
||
|
||
// /** 键盘滚动位置监听 */
|
||
// void scrollListener() {
|
||
// // 保存当前滑动位置,这里假设使用SharedPreferences存储位置为"scroll_position" data
|
||
// FastData.getInstance().setMarkingKeyboardSlidingPosition(MarkingKeyboardSlidingPosition(
|
||
// id: widget.markingUserId,
|
||
// questionNum: widget.data.questionNum,
|
||
// position: _scrollController.position.pixels,
|
||
// ));
|
||
// }
|
||
|
||
// @override
|
||
// void didChangeDependencies() {
|
||
// super.didChangeDependencies();
|
||
// // 获取历史滑动位置,这里假设使用SharedPreferences存储位置为"scroll_position"
|
||
// FastData.getInstance().getMarkingKeyboardSlidingPosition().then((historyPosition) {
|
||
// print('键盘滑动位置:${historyPosition?.toJson()}');
|
||
// // 检查是否有历史滑动位置并且ListView已经完成渲染
|
||
// bool flag = historyPosition != null &&
|
||
// historyPosition.position >= 0 &&
|
||
// _scrollController.hasClients &&
|
||
// historyPosition.questionNum == widget.data.questionNum &&
|
||
// historyPosition.id == widget.markingUserId;
|
||
// if (flag) {
|
||
// // 使用JumpTo或AnimateTo方法滚动到历史位置
|
||
// _scrollController.jumpTo(historyPosition.position);
|
||
// // _scrollController.animateTo(
|
||
// // historyPosition.position,
|
||
// // duration: Duration(milliseconds: 350),
|
||
// // curve: Curves.easeInOut,
|
||
// // );
|
||
// }
|
||
// });
|
||
// }
|
||
|
||
// @override
|
||
// void dispose() {
|
||
// super.dispose();
|
||
|
||
// _scrollController
|
||
// ..removeListener(scrollListener)
|
||
// ..dispose();
|
||
// _markingKeyboardListener();
|
||
// _markingSubtopicSwitchingListener();
|
||
// _animationController
|
||
// ..removeListener(toUp)
|
||
// ..dispose();
|
||
// eventCancel();
|
||
// }
|
||
|
||
// /// 键盘计算数据
|
||
// /// @params localScoreInterval 本地设置分值步长
|
||
// /// @params sort 键盘排序方式
|
||
// void initKeyboardSuper(double? localScoreInterval, SortKeyboard sort) {
|
||
// double scoreInterval = widget.data.scoreInterval; // 服务器针对当前实体设置的分值步长
|
||
// if (localScoreInterval != null && localScoreInterval != 0 && localScoreInterval != scoreInterval) {
|
||
// scoreInterval = localScoreInterval;
|
||
// }
|
||
// double totalScore = widget.hasSubtopic
|
||
// ? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
// : widget.totalScore;
|
||
|
||
// if (scoreInterval == 0) scoreInterval = 1;
|
||
// initKeyboard(totalScore, scoreInterval, sort);
|
||
// }
|
||
|
||
// /// 初始化键盘
|
||
// /// @params {double} totalScore 总分
|
||
// /// @params {double} scoreInterval 小分步长
|
||
// void initKeyboard(double totalScore, double scoreInterval, SortKeyboard sort) {
|
||
// tens.clear();
|
||
// int floorScore = totalScore.floor(); // 总分向下取整
|
||
// int singleDigit = floorScore; // 个位小数
|
||
// int numsLength = singleDigit;
|
||
// if (floorScore > 10) {
|
||
// singleDigit = 9;
|
||
// for (var i = 10; i < floorScore; i += 10) {
|
||
// tens.add(i);
|
||
// }
|
||
// }
|
||
// numsLength = ((numsLength - (numsLength % scoreInterval)) / scoreInterval).floor();
|
||
|
||
// /// +1 添加满分
|
||
// subNums = List.generate(numsLength + 1, (e) => e * scoreInterval); // 小分键盘
|
||
|
||
// // 加一个总分
|
||
// if (numsLength * scoreInterval < totalScore) subNums.add(totalScore);
|
||
// nums = jsonDecode(jsonEncode(subNums)); // 辅助键盘的小分键盘
|
||
// if (sort != SortKeyboard.FULL_AND_AERO_TOP) {
|
||
// if (totalScore > 19) {
|
||
// nums = nums.reversed.toList();
|
||
// } else {
|
||
// nums = nums.reversed.where((e) => e <= 10).toList();
|
||
// }
|
||
// subNums = subNums.reversed.toList();
|
||
// }
|
||
|
||
// // // 计算关闭辅助键盘后的小键盘
|
||
// // if (floorScore > 10) {
|
||
// // int a = scoreInterval == 0.5 ? floorScore * 2 : floorScore;
|
||
// // subNums = List.generate(a+1, (e) => e * scoreInterval); // 小分键盘
|
||
// // }
|
||
// }
|
||
|
||
// /// 打分
|
||
// /// @params {num} fraction 分数
|
||
// /// @params {bool} isTens 十位分数
|
||
// /// @params {bool} fullScore 满分
|
||
// Future<void> marking({required num fraction, String? strScore, bool isTens = false, bool fullScore = false}) async {
|
||
// // 十位
|
||
// if (!fullScore && isTens) {
|
||
// bool cleanScore = _tensVal == fraction;
|
||
// if (!cleanScore) {
|
||
// _tensVal = fraction;
|
||
// } else {
|
||
// _tensVal = null;
|
||
// toUpState(setState, () => _smallScore = null, mounted);
|
||
// }
|
||
// return await widget.synchroScore(
|
||
// score: fraction.toDouble(),
|
||
// continueScoring: true,
|
||
// hasSubtopic: widget.hasSubtopic,
|
||
// cleanScore: cleanScore,
|
||
// );
|
||
// }
|
||
|
||
// toUpState(setState, () => _smallScore = strScore, mounted);
|
||
// EasyLoading.show(status: 'loading...');
|
||
// try {
|
||
// double theScore = fraction.toDouble();
|
||
// if (fullScore) {
|
||
// // 满分
|
||
// theScore = widget.hasSubtopic
|
||
// ? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
// : fraction.toDouble();
|
||
// } else if (_tensVal != null) {
|
||
// // 有十位数
|
||
// theScore = (_tensVal! + fraction).toDouble();
|
||
// }
|
||
|
||
// if (theScore > widget.totalScore) {
|
||
// return ToastUtils.showInfo('评分已大于总分,请重新评分');
|
||
// }
|
||
|
||
// await widget
|
||
// .synchroScore(
|
||
// score: theScore,
|
||
// continueScoring: false,
|
||
// hasSubtopic: widget.hasSubtopic,
|
||
// )
|
||
// .then((_) {
|
||
// if (widget.hasSubtopic) {
|
||
// // 是否有小题
|
||
// List<SubQuestions> subQuestionDetailList = widget.data.subQuestionDetailList;
|
||
|
||
// if (subQuestionDetailList.map((e) => e.completeRating).contains(false)) {
|
||
// setTimeOut(100, () => toUpState(setState, () => _smallScore = null, mounted));
|
||
// return;
|
||
// }
|
||
// }
|
||
// widget.submitCall(); // 提交
|
||
// });
|
||
// } catch (e) {
|
||
// toPrint(val: e.toString());
|
||
// } finally {
|
||
// EasyLoading.dismiss();
|
||
// }
|
||
// }
|
||
|
||
// @override
|
||
// Widget build(BuildContext context) {
|
||
// DoMarkingKeyboardModel thePreference = ref.watch(markingKeyboardProvider);
|
||
// bool henping = thePreference.screenDirection == ScreenDirection.HORIZONTAL_SCREEN; // 屏幕方向
|
||
// SortKeyboard sort = thePreference.sort!;
|
||
|
||
// if (!isRight) {
|
||
// return Container();
|
||
// }
|
||
// // 当前试题有无小题,有小题就是当前小题的总分,无小题就是当前试题的总分
|
||
// double newTotalScore = widget.hasSubtopic
|
||
// ? widget.data.subQuestionDetailList[widget.subtopicIndex].subQuestionScore
|
||
// : widget.totalScore;
|
||
|
||
// // 已经选中辅助键盘的分数,扣除十位分数剩余分数差值
|
||
// double dValue = _tensVal != null ? newTotalScore - _tensVal!.toDouble() : newTotalScore; // 差值
|
||
|
||
// double animationVal = _animationController.value.h;
|
||
// // 右侧键盘
|
||
// return Container(
|
||
// width: henping ? animationVal : animationVal - 16.h,
|
||
// // width: animationVal,
|
||
// margin: EdgeInsets.only(top: 0.6.w),
|
||
// child: Row(
|
||
// children: [
|
||
// // 辅助栏
|
||
// SizedBox(
|
||
// width: animationVal - (henping ? 72.h : 72.h),
|
||
// child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||
// GestureDetector(
|
||
// onTap: () {
|
||
// easyThrottle('toMarkingVal', () => marking(fraction: widget.totalScore, fullScore: true),
|
||
// duration: easyThrottleTime);
|
||
// },
|
||
// child: Container(
|
||
// height: 58.h,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// color: const Color.fromRGBO(4, 201, 208, 1),
|
||
// borderRadius: BorderRadius.all(Radius.circular(1.w)),
|
||
// ),
|
||
// child: quickText(
|
||
// '满分',
|
||
// size: 17.sp,
|
||
// fontWeight: FontWeight.w400,
|
||
// color: const Color.fromRGBO(255, 255, 255, 1),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ...tens.map((e) {
|
||
// return InkWell(
|
||
// onTap: () {
|
||
// easyThrottle('toMarkingVal', () => marking(fraction: e, isTens: true), duration: easyThrottleTime);
|
||
// },
|
||
// child: Container(
|
||
// height: 58.h,
|
||
// margin: EdgeInsets.only(top: 1.w),
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// color: _tensVal == e ? Colors.amber[800] : Theme.of(context).primaryColor,
|
||
// borderRadius: BorderRadius.all(Radius.circular(1.w)),
|
||
// ),
|
||
// child: quickText(
|
||
// '$e+',
|
||
// size: 17.sp,
|
||
// fontWeight: FontWeight.w500,
|
||
// color: const Color.fromRGBO(255, 255, 255, 1),
|
||
// ),
|
||
// ),
|
||
// );
|
||
// }).toList()
|
||
// ]),
|
||
// ),
|
||
// // 小分栏
|
||
// Expanded(
|
||
// child: Container(
|
||
// width: henping ? 72.h : 60.h,
|
||
// // width: 72.h,
|
||
// padding: EdgeInsets.symmetric(horizontal: 4.h, vertical: 4.h),
|
||
// decoration: BoxDecoration(
|
||
// boxShadow: [
|
||
// BoxShadow(
|
||
// color: const Color.fromRGBO(46, 91, 255, 0.2),
|
||
// offset: Offset(0, 8.w), //阴影y轴偏移量
|
||
// blurRadius: 1, //阴影模糊程度
|
||
// spreadRadius: 2, //阴影扩散程度
|
||
// )
|
||
// ],
|
||
// color: const Color.fromRGBO(255, 255, 255, 1),
|
||
// ),
|
||
// child: ListView(
|
||
// controller: _scrollController,
|
||
// children: [
|
||
// if ([SortKeyboard.FULL_AND_AERO_TOP, SortKeyboard.FULL_AND_AERO_TOP_INVERTED_ORDER].contains(sort))
|
||
// Ink(
|
||
// color: const Color.fromRGBO(249, 250, 254, 1),
|
||
// child: InkWell(
|
||
// splashColor: Colors.cyanAccent,
|
||
// onTap: () {
|
||
// easyThrottle(
|
||
// 'toMarkingVal',
|
||
// () => marking(
|
||
// fraction: widget.totalScore, fullScore: true, strScore: widget.totalScore.toString()),
|
||
// duration: easyThrottleTime);
|
||
// },
|
||
// child: Container(
|
||
// width: double.infinity,
|
||
// height: 56.h,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// border: Border.all(
|
||
// width: 1.h,
|
||
// color: const Color.fromRGBO(224, 230, 255, 1),
|
||
// ),
|
||
// borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
// ),
|
||
// child: quickText('满分', size: 15.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// if (SortKeyboard.FULL_AND_AERO_TOP_INVERTED_ORDER == sort)
|
||
// Ink(
|
||
// color: const Color.fromRGBO(249, 250, 254, 1),
|
||
// child: InkWell(
|
||
// splashColor: Colors.cyanAccent,
|
||
// onTap: () {
|
||
// easyThrottle('toMarkingVal', () => marking(fraction: 0, fullScore: true, strScore: '0'),
|
||
// duration: easyThrottleTime);
|
||
// },
|
||
// child: Container(
|
||
// width: double.infinity,
|
||
// height: 56.h,
|
||
// margin: EdgeInsets.only(top: 3.h),
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// border: Border.all(
|
||
// width: 1.h,
|
||
// color: const Color.fromRGBO(224, 230, 255, 1),
|
||
// ),
|
||
// borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
// ),
|
||
// child: quickText('零分', size: 15.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ...(!_openAuxiliary && newTotalScore > 10 ? subNums : nums).map((e) {
|
||
// String strScore = getDoubleRemoveZero(e);
|
||
// bool isCurrentSelect = _smallScore == strScore; // 当前选中
|
||
|
||
// if (e == 0 && SortKeyboard.FULL_AND_AERO_TOP_INVERTED_ORDER == sort) {
|
||
// return Container();
|
||
// }
|
||
// bool effective = e <= dValue;
|
||
// return Ink(
|
||
// child: InkWell(
|
||
// splashColor: Colors.cyanAccent,
|
||
// onTap: effective
|
||
// ? () => easyThrottle('toMarkingVal', () => marking(fraction: e, strScore: strScore),
|
||
// duration: easyThrottleTime)
|
||
// : null,
|
||
// child: Container(
|
||
// width: double.infinity,
|
||
// height: 56.h,
|
||
// margin: EdgeInsets.only(top: 3.h),
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// border: Border.all(
|
||
// width: 1.h,
|
||
// color: const Color.fromRGBO(224, 230, 255, 1),
|
||
// ),
|
||
// color: isCurrentSelect
|
||
// ? Theme.of(context).primaryColor
|
||
// : effective
|
||
// ? const Color.fromRGBO(249, 250, 254, 1)
|
||
// : Colors.grey[300],
|
||
// borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
// ),
|
||
// child: quickText(
|
||
// strScore == '0' ? '零分' : strScore,
|
||
// size: 15.sp,
|
||
// color: isCurrentSelect ? Colors.white : const Color.fromRGBO(148, 163, 182, 1),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// );
|
||
// }).toList(),
|
||
// if (sort == SortKeyboard.INVERTED_ORDER)
|
||
// Ink(
|
||
// color: const Color.fromRGBO(249, 250, 254, 1),
|
||
// child: InkWell(
|
||
// splashColor: Colors.cyanAccent,
|
||
// onTap: () {
|
||
// easyThrottle(
|
||
// 'toMarkingVal',
|
||
// () => marking(
|
||
// fraction: widget.totalScore, fullScore: true, strScore: widget.totalScore.toString()),
|
||
// duration: easyThrottleTime);
|
||
// },
|
||
// child: Container(
|
||
// width: double.infinity,
|
||
// height: 56.h,
|
||
// margin: EdgeInsets.only(top: 3.h),
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// border: Border.all(
|
||
// width: 1.h,
|
||
// color: const Color.fromRGBO(224, 230, 255, 1),
|
||
// ),
|
||
// borderRadius: BorderRadius.all(Radius.circular(2.w)),
|
||
// ),
|
||
// child: quickText('满分', size: 15.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ],
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ],
|
||
// ),
|
||
// );
|
||
// }
|
||
// }
|