play_step.dart 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_chinese_chees/models/game_event.dart';
  3. import '../global.dart';
  4. import '../models/game_manager.dart';
  5. /// 着法列表
  6. class PlayStep extends StatefulWidget {
  7. final BoxDecoration? decoration;
  8. final double width;
  9. const PlayStep({Key? key, this.decoration, required this.width})
  10. : super(key: key);
  11. @override
  12. State<PlayStep> createState() => PlayStepState();
  13. }
  14. class PlayStepState extends State<PlayStep> {
  15. final List<String> steps = [''];
  16. final ScrollController _controller = ScrollController(keepScrollOffset: true);
  17. final GameManager gamer = GameManager.instance;
  18. int currentStep = 0;
  19. @override
  20. void initState() {
  21. super.initState();
  22. gamer.on<GameStepEvent>(updateStep);
  23. steps.addAll(gamer.getSteps());
  24. currentStep = gamer.currentStep;
  25. }
  26. @override
  27. void dispose() {
  28. gamer.off<GameStepEvent>(updateStep);
  29. super.dispose();
  30. }
  31. void updateStep(GameEvent event) {
  32. String message = event.data!;
  33. if (message.isEmpty || !mounted) return;
  34. if (message == 'clear') {
  35. setState(() {
  36. currentStep = gamer.currentStep - 1;
  37. steps.removeRange(currentStep + 2, steps.length);
  38. });
  39. } else if (message == 'step') {
  40. setState(() {
  41. currentStep = gamer.currentStep;
  42. });
  43. } else {
  44. setState(() {
  45. message.split('\n').forEach((element) {
  46. steps.add(element);
  47. });
  48. currentStep = steps.length - 1;
  49. });
  50. }
  51. Future.delayed(const Duration(milliseconds: 16)).then((value) {
  52. ScrollPositionWithSingleContext position =
  53. _controller.position as ScrollPositionWithSingleContext;
  54. _controller.animateTo(
  55. position.maxScrollExtent,
  56. duration: const Duration(milliseconds: 100),
  57. curve: Curves.easeOut,
  58. );
  59. });
  60. }
  61. @override
  62. Widget build(BuildContext context) {
  63. return Container(
  64. width: widget.width,
  65. padding: const EdgeInsets.all(10),
  66. decoration: widget.decoration,
  67. child: ListView.builder(
  68. controller: _controller,
  69. itemCount: steps.length,
  70. itemBuilder: (context, index) => GestureDetector(
  71. onTap: () {
  72. if (!gamer.canBacktrace) return;
  73. gamer.loadHistory(index - 1);
  74. setState(() {
  75. currentStep = index;
  76. });
  77. },
  78. child: Container(
  79. height: 23,
  80. padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
  81. alignment: Alignment.centerLeft,
  82. decoration: BoxDecoration(
  83. color: currentStep == index ? Colors.black26 : Colors.transparent,
  84. ),
  85. child: (index > 0 && index % 2 == 1)
  86. ? Text('${(index + 1) ~/ 2}.${steps[index]}')
  87. : Text(
  88. ' ${index == 0 ? context.l10n.stepStart : steps[index]}',
  89. ),
  90. ),
  91. ),
  92. ),
  93. );
  94. }
  95. }