dialog_check_rich.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. import 'dart:convert';
  2. import 'package:assets_audio_player/assets_audio_player.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:get/get.dart';
  5. import 'package:trackoffical_app/generated/assets.dart';
  6. import 'package:trackoffical_app/model/m_control_point.dart';
  7. import 'package:trackoffical_app/screen.dart';
  8. import 'package:trackoffical_app/utils.dart';
  9. import '../../../model/cp_extra_info.dart';
  10. import '../../../model/cp_extra_info_choice_question.dart';
  11. import '../../../styles/theme.dart';
  12. import 'dialog_base.dart';
  13. class DialogCheckRich extends StatefulWidget {
  14. const DialogCheckRich(
  15. {super.key, required this.point, required this.offAfter});
  16. final Duration offAfter;
  17. final MControlPoint point;
  18. @override
  19. State<StatefulWidget> createState() {
  20. return DialogCheckRichState();
  21. }
  22. }
  23. class DialogCheckRichState extends State<DialogCheckRich> {
  24. Duration? offAfter;
  25. var isActive = true;
  26. final createAt = DateTime.now();
  27. int? selectedIndex;
  28. var isFinish = false;
  29. var beanCount = 1;
  30. final _audioPlayer = AssetsAudioPlayer.newPlayer();
  31. @override
  32. void initState() {
  33. super.initState();
  34. workCount();
  35. }
  36. @override
  37. void dispose() {
  38. isActive = false;
  39. _audioPlayer.dispose();
  40. super.dispose();
  41. }
  42. void _setFinish(){
  43. setState(() {
  44. isFinish = true;
  45. });
  46. _audioPlayer.open(
  47. Audio(Assets.soundAfterAnswer),
  48. autoStart: true,
  49. showNotification: false,
  50. );
  51. 3.seconds.delay().then((value){
  52. if(isActive && Get.isOverlaysOpen){
  53. Get.back();
  54. }
  55. });
  56. }
  57. Future<void> workCount() async {
  58. while (isActive) {
  59. if (isFinish) {
  60. return;
  61. }
  62. final offAfter = DateTime.now().difference(createAt);
  63. setState(() {
  64. this.offAfter = offAfter;
  65. });
  66. if (offAfter > widget.offAfter) {
  67. _setFinish();
  68. }
  69. await Future.delayed(100.milliseconds);
  70. }
  71. }
  72. @override
  73. Widget build(BuildContext context) {
  74. return isFinish ? wFinish() : DefaultTextStyle(
  75. style: context.textTheme.titleLarge ??
  76. const TextStyle(), child: wMain());
  77. }
  78. Widget wMain() {
  79. final extraInfo = widget.point.extraInfo;
  80. final mainHeight = extraInfo != null ? 261.45.rpx : 358.78.rpx;
  81. final point = widget.point;
  82. final style = context.textTheme.titleLarge ??
  83. const TextStyle().copyWith(
  84. color: const Color(0xff333333),
  85. fontSize: 61.0.rpx,
  86. fontWeight: FontWeight.w700);
  87. var title = point.snString.isNotEmpty ? '${point.snString}点' : '';
  88. if (point.areaId.isNotEmpty) {
  89. title += '(${point.areaId})';
  90. }
  91. var imageSrc = 'assets/images/ic_cp.png';
  92. if (point.isStart) {
  93. imageSrc = 'assets/images/ic_cp_start.png';
  94. }
  95. if (point.isFinish) {
  96. imageSrc = 'assets/images/ic_cp_finish.png';
  97. }
  98. final children = <Widget>[];
  99. if (extraInfo != null) {
  100. children.add(wExtraInfo(extraInfo, mainHeight));
  101. }
  102. children.add(Container(
  103. height: mainHeight,
  104. margin: EdgeInsets.only(left: 47.71.rpx, right: 47.71.rpx),
  105. decoration: BoxDecoration(
  106. color: Colors.white,
  107. borderRadius: BorderRadius.circular(17.18.rpx),
  108. boxShadow: [
  109. BoxShadow(
  110. color: const Color(0x29000000),
  111. offset: Offset(5.73.rpx, 5.73.rpx),
  112. blurRadius: 11.45.rpx,
  113. spreadRadius: 11.45.rpx,
  114. )
  115. ]),
  116. padding: EdgeInsets.only(
  117. left: 60.0.rpx, right: 60.0.rpx, top: 20.0.rpx, bottom: 20.0.rpx),
  118. child: Column(
  119. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  120. crossAxisAlignment: CrossAxisAlignment.start,
  121. children: [
  122. RichText(
  123. text: TextSpan(text: '打点成功', style: style, children: [
  124. TextSpan(
  125. text: ' +${widget.point.checkAfterPrev.toMinSecondString()}',
  126. style:
  127. style.copyWith(color: Colors.orange, fontSize: 30.53.rpx))
  128. ])),
  129. Row(
  130. crossAxisAlignment: CrossAxisAlignment.end,
  131. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  132. children: [
  133. Row(
  134. mainAxisSize: MainAxisSize.min,
  135. children: [
  136. Image.asset(imageSrc, height: 37.18.rpx),
  137. SizedBox(width: 15.3.rpx),
  138. Text(title, style: style.copyWith(fontSize: 30.5.rpx))
  139. ],
  140. ),
  141. bean(1, 30.53.rpx),
  142. ],
  143. )
  144. ],
  145. ),
  146. ));
  147. int? second;
  148. if (offAfter != null) {
  149. second =
  150. ((widget.offAfter.inMilliseconds - offAfter!.inMilliseconds) / 1000)
  151. .ceil();
  152. }
  153. return GestureDetector(
  154. // onTap: onBack,
  155. child: Container(
  156. width: context.width,
  157. height: context.height,
  158. color: const Color(0xB8000000),
  159. alignment: Alignment.center,
  160. child: Center(
  161. child: Column(
  162. mainAxisSize: MainAxisSize.min,
  163. children: [
  164. Stack(
  165. children: children,
  166. ),
  167. SizedBox(height: 50.0.rpx),
  168. Text(
  169. second?.toString() ?? '',
  170. style: context.textTheme.titleLarge?.copyWith(
  171. fontSize: 150.0.rpx, color: const Color(0xffff870d)),
  172. )
  173. ],
  174. ),
  175. ),
  176. ),
  177. );
  178. }
  179. Widget wFinish() {
  180. return GestureDetector(
  181. onTap: onBack,
  182. child: Container(
  183. width: context.width,
  184. height: context.height,
  185. color: const Color(0xB8000000),
  186. alignment: Alignment.center,
  187. child: Center(
  188. child: DefaultTextStyle(
  189. style: context.textTheme.titleLarge ??
  190. const TextStyle().copyWith(
  191. color: const Color(0xffa0a0a0), fontSize: 45.8.rpx),
  192. child: Column(mainAxisSize: MainAxisSize.min, children: [
  193. bean(beanCount, 74.43.rpx),
  194. SizedBox(height: 48.9.rpx),
  195. Text(
  196. '共获得$beanCount个百味豆',
  197. style: const TextStyle(color: Color(0xffa0a0a0)),
  198. )
  199. ])))),
  200. );
  201. }
  202. Future<void> onBack() async {
  203. Get.back();
  204. }
  205. Widget wExtraInfo(CPExtraInfo extraInfo, double mainHeight) {
  206. Widget child;
  207. if (extraInfo is CPExtraInfoChoiceQuestion) {
  208. child = wExtraInfoChoiceQuestion(extraInfo);
  209. } else {
  210. throw UnimplementedError('wExtraInfo: $extraInfo 未实现');
  211. }
  212. return Container(
  213. margin: EdgeInsets.only(left: 64.8.rpx, right: 64.8.rpx),
  214. padding: EdgeInsets.only(
  215. left: 36.8.rpx,
  216. right: 36.8.rpx,
  217. top: mainHeight + 64.0.rpx,
  218. bottom: 40.0.rpx),
  219. decoration: BoxDecoration(
  220. color: Colors.white, borderRadius: BorderRadius.circular(17.18.rpx)),
  221. // child: child,
  222. child: DefaultTextStyle(
  223. style: context.textTheme.titleLarge ??
  224. const TextStyle().copyWith(
  225. color: Colors.black,
  226. fontSize: 41.98.rpx,
  227. fontWeight: FontWeight.w700),
  228. child: child,
  229. ),
  230. );
  231. }
  232. Widget wExtraInfoChoiceQuestion(CPExtraInfoChoiceQuestion extraInfo) {
  233. final answers = <Widget>[];
  234. var ascii = 65;
  235. for (var i = 0; i < extraInfo.answers.length; i++) {
  236. final one = extraInfo.answers[i];
  237. final sn = const Utf8Codec().decode([ascii]);
  238. final selected = i == selectedIndex;
  239. answers.add(GestureDetector(
  240. onTap: () async {
  241. if (selectedIndex == null) {
  242. setState(() {
  243. selectedIndex = i;
  244. });
  245. if (i == extraInfo.rightIndex) {
  246. beanCount += extraInfo.beanCount;
  247. }
  248. widget.point.userAnswerIndex = selectedIndex;
  249. widget.point.isAnswerCorrect =
  250. selectedIndex == extraInfo.rightIndex;
  251. await 1.seconds.delay();
  252. _setFinish();
  253. }
  254. },
  255. child: Container(
  256. padding: EdgeInsets.only(top: 15.0.rpx, bottom: 15.0.rpx),
  257. color: Colors.white,
  258. child: Row(
  259. mainAxisAlignment: MainAxisAlignment.start,
  260. crossAxisAlignment: CrossAxisAlignment.start,
  261. children: [
  262. Image.asset(
  263. selected
  264. ? Assets.imagesIcRadioSelected
  265. : Assets.imagesIcRadio,
  266. height: 53.44.rpx,
  267. width: 53.44.rpx,
  268. ),
  269. SizedBox(
  270. width: 32.0.rpx,
  271. ),
  272. Expanded(child: Text(
  273. '$sn. $one',
  274. style: TextStyle(
  275. color:
  276. selected ? const Color(0xff00a0ff) : Colors.black),
  277. softWrap: true
  278. ))
  279. ,
  280. ],
  281. ))));
  282. ascii++;
  283. }
  284. return Column(
  285. mainAxisSize: MainAxisSize.min,
  286. crossAxisAlignment: CrossAxisAlignment.start,
  287. children: [
  288. Text(extraInfo.question),
  289. SizedBox(height: 39.0.rpx),
  290. Row(
  291. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  292. children: [
  293. Expanded(
  294. child: Column(
  295. mainAxisSize: MainAxisSize.min,
  296. crossAxisAlignment: CrossAxisAlignment.start,
  297. children: answers)),
  298. bean(extraInfo.beanCount, 30.53.rpx),
  299. ],
  300. )
  301. ],
  302. );
  303. }
  304. }
  305. class _Empty extends StatelessWidget {
  306. @override
  307. Widget build(BuildContext context) {
  308. SizeFit.screenInit(context);
  309. return const Scaffold(
  310. floatingActionButton: FloatingActionButton(onPressed: _showDialog),
  311. );
  312. }
  313. }
  314. Future<void> _showDialog() async {
  315. if (Get.isOverlaysOpen) {
  316. Get.back();
  317. }
  318. final info = CPExtraInfoChoiceQuestion()
  319. ..question = '计算题 23 + 8 - 6 = ?'
  320. ..answers = ['22', '2312312312311', '242323', '21231231211111231235']
  321. ..rightIndex = 3;
  322. Get.dialog(
  323. DialogCheckRich(
  324. point: MControlPoint()
  325. ..sn = '3'
  326. ..areaId = 'A55'
  327. ..checkAfterPrev = 2.1.minutes
  328. ..extraInfo = info,
  329. offAfter: 5.seconds,
  330. ),
  331. );
  332. }
  333. void main() async {
  334. runApp(GetMaterialApp(theme: appThemeData(), home: _Empty()));
  335. }