You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
12 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_bloc/flutter_bloc.dart';
  4. import 'package:flutter_riverpod/flutter_riverpod.dart';
  5. import 'package:flutter_svg/flutter_svg.dart';
  6. import 'package:my_flutter_puzzle/application/states/image_splitter_state.dart';
  7. import 'package:my_flutter_puzzle/application/states/puzzle_state.dart';
  8. import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart';
  9. import 'package:my_flutter_puzzle/models/puzzle_data.dart';
  10. import 'package:my_flutter_puzzle/providers.dart';
  11. import 'package:my_flutter_puzzle/res/puzzle_constants.dart';
  12. import 'package:my_flutter_puzzle/screens/level_list/cubit/level_list_cubit.dart';
  13. import 'package:my_flutter_puzzle/screens/lose/lose_screen.dart';
  14. import 'package:my_flutter_puzzle/screens/win/win_screen.dart';
  15. import 'package:my_flutter_puzzle/utils/extensions/context_extension.dart';
  16. import 'package:my_flutter_puzzle/utils/extensions/string_extensions.dart';
  17. import 'package:my_flutter_puzzle/utils/puzzle_solver.dart';
  18. import 'package:my_flutter_puzzle/widgets/photo_screen/image_viewer.dart';
  19. import 'package:my_flutter_puzzle/widgets/solo_screen/count_down_timer_widget.dart';
  20. import 'package:my_flutter_puzzle/widgets/solo_screen/countdown_widget.dart';
  21. import 'package:my_flutter_puzzle/widgets/solo_screen/moves_tiles_widget.dart';
  22. import 'package:my_flutter_puzzle/widgets/solo_screen/puzzle_widget.dart';
  23. import 'package:palette_generator/palette_generator.dart';
  24. import 'package:rive/rive.dart';
  25. class PhotoScreenLarge extends ConsumerStatefulWidget {
  26. const PhotoScreenLarge({
  27. required this.solverClient,
  28. required this.initialPuzzleData,
  29. required this.puzzleSize,
  30. required this.riveController,
  31. required this.duration,
  32. required this.level,
  33. Key? key,
  34. }) : super(key: key);
  35. final PuzzleSolverClient solverClient;
  36. final PuzzleData initialPuzzleData;
  37. final int puzzleSize;
  38. final int duration;
  39. final int level;
  40. final RiveAnimationController riveController;
  41. @override
  42. ConsumerState<ConsumerStatefulWidget> createState() => _SoloScreenLargeState();
  43. }
  44. class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
  45. late final PuzzleSolverClient _solverClient;
  46. late final int _puzzleSize;
  47. late final PuzzleData _initialPuzzleData;
  48. late final RiveAnimationController _riveController;
  49. bool _puzzleSolved = false;
  50. bool _isStartPressed = false;
  51. final double _fontSize = 70.0;
  52. final double _boardSize = 280.0;
  53. final int _spacing = 4;
  54. late double _eachBoxSize;
  55. List<Image>? _previousImages;
  56. Image? _previousImage;
  57. PaletteGenerator? _previousPalette;
  58. int _moves = 0;
  59. int _tiles = 0;
  60. @override
  61. void initState() {
  62. _solverClient = widget.solverClient;
  63. _puzzleSize = widget.puzzleSize;
  64. _eachBoxSize = (_boardSize / _puzzleSize) - (_spacing * (_puzzleSize - 1));
  65. _initialPuzzleData = widget.initialPuzzleData;
  66. _riveController = widget.riveController;
  67. super.initState();
  68. }
  69. @override
  70. Widget build(BuildContext context) {
  71. ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) {
  72. if (next is PuzzleInitializing) {
  73. setState(() {
  74. _isStartPressed = true;
  75. });
  76. }
  77. if (next is PuzzleSolved) {
  78. _puzzleSolved = true;
  79. BlocProvider.of<CountDownTimerCubit>(context).stop();
  80. BlocProvider.of<LevelListCubit>(context).setRecordDuration(
  81. widget.level,
  82. BlocProvider.of<CountDownTimerCubit>(context).getDuration() ?? Duration(minutes: widget.duration),
  83. () {
  84. Future.delayed(const Duration(milliseconds: 500), () {
  85. Navigator.pushReplacement(context, MaterialPageRoute(
  86. builder: (context) {
  87. return WinScreen(
  88. tiles: _tiles,
  89. move: _moves,
  90. level: widget.level,
  91. );
  92. },
  93. ));
  94. });
  95. },
  96. );
  97. }
  98. });
  99. ref.listen(imageSplitterNotifierProvider, (previous, next) {
  100. if (next is ImageSplitterComplete) {
  101. setState(() {
  102. _previousImages = next.images;
  103. _previousImage = next.image;
  104. _previousPalette = next.palette;
  105. });
  106. ref.read(puzzleNotifierProvider(_solverClient).notifier).initializePuzzle(
  107. initialPuzzleData: _initialPuzzleData,
  108. );
  109. }
  110. });
  111. return WillPopScope(
  112. onWillPop: () async {
  113. BlocProvider.of<CountDownTimerCubit>(context).stop();
  114. return true;
  115. },
  116. child: Scaffold(
  117. backgroundColor: const Color(0xff4400CE),
  118. body: SafeArea(
  119. child: Padding(
  120. padding: EdgeInsets.symmetric(
  121. horizontal: context.width * 26 / 812,
  122. ),
  123. child: Column(
  124. children: [
  125. SizedBox(height: context.height * 20 / 375),
  126. SizedBox(
  127. width: context.width,
  128. child: Row(
  129. children: [
  130. SvgPicture.asset('flash'.svgPath),
  131. const SizedBox(width: 8),
  132. Text(
  133. 'Level ${widget.level}',
  134. style: const TextStyle(
  135. color: Colors.white,
  136. fontWeight: FontWeight.bold,
  137. fontSize: 16,
  138. ),
  139. ),
  140. const Spacer(),
  141. CountDownTimerWidget(
  142. duration: widget.duration,
  143. finishCallback: _finishTime,
  144. ),
  145. const Spacer(),
  146. GestureDetector(
  147. onTap: _resetTimer,
  148. child: Container(
  149. width: context.width * 22 / 540,
  150. height: context.width * 22 / 540,
  151. padding: const EdgeInsets.all(5),
  152. margin: const EdgeInsets.symmetric(vertical: 3),
  153. decoration: const BoxDecoration(
  154. color: Colors.white,
  155. shape: BoxShape.circle,
  156. ),
  157. child: SvgPicture.asset('refresh'.svgPath),
  158. ),
  159. ),
  160. ],
  161. ),
  162. ),
  163. SizedBox(height: context.height * 22 / 375),
  164. Row(
  165. crossAxisAlignment: CrossAxisAlignment.start,
  166. children: [
  167. Column(
  168. children: [
  169. ImageViewer(
  170. puzzleSize: _puzzleSize,
  171. previousImage: _previousImage,
  172. previousPalette: _previousPalette,
  173. imageSize: 200,
  174. ),
  175. SizedBox(height: context.height * 30 / 375),
  176. MovesTilesWidget(
  177. solverClient: _solverClient,
  178. fontSize: 16,
  179. callback: (move, tiles) {
  180. _moves = move;
  181. _tiles = tiles;
  182. },
  183. ),
  184. ],
  185. ),
  186. SizedBox(width: context.width * 34 / 812),
  187. SingleChildScrollView(
  188. child: Column(
  189. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  190. children: [
  191. Consumer(
  192. builder: (context, ref, child) {
  193. final state = ref.watch(
  194. imageSplitterNotifierProvider,
  195. );
  196. return state.maybeWhen(
  197. () => PuzzleWidget(
  198. solverClient: _solverClient,
  199. boardSize: _boardSize,
  200. eachBoxSize: _eachBoxSize,
  201. initialPuzzleData: _initialPuzzleData,
  202. fontSize: _fontSize,
  203. images: _previousImages,
  204. kInitialSpeed: kInitialSpeed,
  205. ),
  206. complete: (image, images, palette) {
  207. _previousImages = images;
  208. _previousImage = image;
  209. _previousPalette = palette;
  210. return PuzzleWidget(
  211. solverClient: _solverClient,
  212. boardSize: _boardSize,
  213. eachBoxSize: _eachBoxSize,
  214. initialPuzzleData: _initialPuzzleData,
  215. fontSize: _fontSize,
  216. images: images,
  217. kInitialSpeed: kInitialSpeed,
  218. );
  219. },
  220. orElse: () => PuzzleWidget(
  221. solverClient: _solverClient,
  222. boardSize: _boardSize,
  223. eachBoxSize: _eachBoxSize,
  224. initialPuzzleData: _initialPuzzleData,
  225. fontSize: _fontSize,
  226. images: _previousImages,
  227. kInitialSpeed: kInitialSpeed,
  228. ),
  229. );
  230. },
  231. ),
  232. ],
  233. ),
  234. ),
  235. SizedBox(width: context.width * 32 / 812),
  236. Stack(
  237. alignment: Alignment.center,
  238. children: [
  239. SizedBox(
  240. width: context.width * 126 / 812,
  241. height: context.height * 280 / 375,
  242. child: Image(
  243. image: AssetImage('avatar'.pngPath),
  244. ),
  245. ),
  246. Column(
  247. mainAxisSize: MainAxisSize.max,
  248. crossAxisAlignment: CrossAxisAlignment.end,
  249. mainAxisAlignment: MainAxisAlignment.center,
  250. children: [
  251. CountdownWidget(
  252. isStartPressed: _isStartPressed,
  253. onFinish: () {
  254. BlocProvider.of<CountDownTimerCubit>(context).start();
  255. setState(() {
  256. _isStartPressed = false;
  257. });
  258. },
  259. initialSpeed: kInitialSpeed,
  260. ),
  261. ],
  262. ),
  263. ],
  264. ),
  265. ],
  266. ),
  267. ],
  268. ),
  269. ),
  270. ),
  271. ),
  272. );
  273. }
  274. void _finishTime() {
  275. if (!_puzzleSolved) {
  276. Future.delayed(const Duration(milliseconds: 1500), () {
  277. Navigator.push(context, MaterialPageRoute(
  278. builder: (context) {
  279. return LoseScreen(tiles: _tiles, move: _moves);
  280. },
  281. )).then((value) {
  282. if (value == true) {
  283. BlocProvider.of<CountDownTimerCubit>(context).reset();
  284. BlocProvider.of<CountDownTimerCubit>(context).start();
  285. } else {
  286. Navigator.pop(context);
  287. }
  288. });
  289. });
  290. }
  291. }
  292. void _resetTimer() {
  293. BlocProvider.of<CountDownTimerCubit>(context).reset();
  294. }
  295. }