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.

331 lines
13 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
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. Timer timer = Timer(
  68. const Duration(seconds: 10),
  69. () {
  70. _puzzleSolved = true;
  71. BlocProvider.of<CountDownTimerCubit>(context).stop();
  72. BlocProvider.of<LevelListCubit>(context).setRecordDuration(
  73. widget.level,
  74. BlocProvider.of<CountDownTimerCubit>(context).getDuration() ?? Duration(minutes: widget.duration),
  75. () {
  76. Future.delayed(const Duration(milliseconds: 500), () {
  77. Navigator.pushReplacement(context, MaterialPageRoute(
  78. builder: (context) {
  79. return WinScreen(
  80. tiles: _tiles,
  81. move: _moves,
  82. level: widget.level,
  83. );
  84. },
  85. ));
  86. });
  87. },
  88. );
  89. },
  90. );
  91. super.initState();
  92. }
  93. @override
  94. Widget build(BuildContext context) {
  95. ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) {
  96. if (next is PuzzleInitializing) {
  97. setState(() {
  98. _isStartPressed = true;
  99. });
  100. }
  101. if (next is PuzzleSolved) {
  102. _puzzleSolved = true;
  103. BlocProvider.of<CountDownTimerCubit>(context).stop();
  104. BlocProvider.of<LevelListCubit>(context).setRecordDuration(
  105. widget.level,
  106. BlocProvider.of<CountDownTimerCubit>(context).getDuration() ?? Duration(minutes: widget.duration),
  107. () {
  108. Future.delayed(const Duration(milliseconds: 500), () {
  109. Navigator.pushReplacement(context, MaterialPageRoute(
  110. builder: (context) {
  111. return WinScreen(
  112. tiles: _tiles,
  113. move: _moves,
  114. level: widget.level,
  115. );
  116. },
  117. ));
  118. });
  119. },
  120. );
  121. }
  122. });
  123. ref.listen(imageSplitterNotifierProvider, (previous, next) {
  124. if (next is ImageSplitterComplete) {
  125. setState(() {
  126. _previousImages = next.images;
  127. _previousImage = next.image;
  128. _previousPalette = next.palette;
  129. });
  130. ref.read(puzzleNotifierProvider(_solverClient).notifier).initializePuzzle(
  131. initialPuzzleData: _initialPuzzleData,
  132. );
  133. }
  134. });
  135. return WillPopScope(
  136. onWillPop: () async {
  137. BlocProvider.of<CountDownTimerCubit>(context).stop();
  138. return true;
  139. },
  140. child: Scaffold(
  141. backgroundColor: const Color(0xff4400CE),
  142. body: SafeArea(
  143. child: Padding(
  144. padding: EdgeInsets.symmetric(
  145. horizontal: context.width * 26 / 812,
  146. ),
  147. child: Column(
  148. children: [
  149. SizedBox(height: context.height * 20 / 375),
  150. SizedBox(
  151. width: context.width,
  152. child: Row(
  153. children: [
  154. SvgPicture.asset('flash'.svgPath),
  155. const SizedBox(width: 8),
  156. Text(
  157. 'Level ${widget.level}',
  158. style: const TextStyle(
  159. color: Colors.white,
  160. fontWeight: FontWeight.bold,
  161. fontSize: 16,
  162. ),
  163. ),
  164. const Spacer(),
  165. CountDownTimerWidget(
  166. duration: widget.duration,
  167. finishCallback: _finishTime,
  168. ),
  169. const Spacer(),
  170. GestureDetector(
  171. onTap: _resetTimer,
  172. child: Container(
  173. width: context.width * 22 / 540,
  174. height: context.width * 22 / 540,
  175. padding: const EdgeInsets.all(5),
  176. margin: const EdgeInsets.symmetric(vertical: 3),
  177. decoration: const BoxDecoration(
  178. color: Colors.white,
  179. shape: BoxShape.circle,
  180. ),
  181. child: SvgPicture.asset('refresh'.svgPath),
  182. ),
  183. ),
  184. ],
  185. ),
  186. ),
  187. SizedBox(height: context.height * 22 / 375),
  188. Row(
  189. crossAxisAlignment: CrossAxisAlignment.start,
  190. children: [
  191. Column(
  192. children: [
  193. ImageViewer(
  194. puzzleSize: _puzzleSize,
  195. previousImage: _previousImage,
  196. previousPalette: _previousPalette,
  197. imageSize: 200,
  198. ),
  199. SizedBox(height: context.height * 30 / 375),
  200. MovesTilesWidget(
  201. solverClient: _solverClient,
  202. fontSize: 16,
  203. callback: (move, tiles) {
  204. _moves = move;
  205. _tiles = tiles;
  206. },
  207. ),
  208. ],
  209. ),
  210. SizedBox(width: context.width * 34 / 812),
  211. SingleChildScrollView(
  212. child: Column(
  213. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  214. children: [
  215. Consumer(
  216. builder: (context, ref, child) {
  217. final state = ref.watch(
  218. imageSplitterNotifierProvider,
  219. );
  220. return state.maybeWhen(
  221. () => PuzzleWidget(
  222. solverClient: _solverClient,
  223. boardSize: _boardSize,
  224. eachBoxSize: _eachBoxSize,
  225. initialPuzzleData: _initialPuzzleData,
  226. fontSize: _fontSize,
  227. images: _previousImages,
  228. kInitialSpeed: kInitialSpeed,
  229. ),
  230. complete: (image, images, palette) {
  231. _previousImages = images;
  232. _previousImage = image;
  233. _previousPalette = palette;
  234. return PuzzleWidget(
  235. solverClient: _solverClient,
  236. boardSize: _boardSize,
  237. eachBoxSize: _eachBoxSize,
  238. initialPuzzleData: _initialPuzzleData,
  239. fontSize: _fontSize,
  240. images: images,
  241. kInitialSpeed: kInitialSpeed,
  242. );
  243. },
  244. orElse: () => PuzzleWidget(
  245. solverClient: _solverClient,
  246. boardSize: _boardSize,
  247. eachBoxSize: _eachBoxSize,
  248. initialPuzzleData: _initialPuzzleData,
  249. fontSize: _fontSize,
  250. images: _previousImages,
  251. kInitialSpeed: kInitialSpeed,
  252. ),
  253. );
  254. },
  255. ),
  256. ],
  257. ),
  258. ),
  259. SizedBox(width: context.width * 32 / 812),
  260. Stack(
  261. alignment: Alignment.center,
  262. children: [
  263. SizedBox(
  264. width: context.width * 126 / 812,
  265. height: context.height * 280 / 375,
  266. child: Image(
  267. image: AssetImage('avatar'.pngPath),
  268. ),
  269. ),
  270. Column(
  271. mainAxisSize: MainAxisSize.max,
  272. crossAxisAlignment: CrossAxisAlignment.end,
  273. mainAxisAlignment: MainAxisAlignment.center,
  274. children: [
  275. CountdownWidget(
  276. isStartPressed: _isStartPressed,
  277. onFinish: () {
  278. BlocProvider.of<CountDownTimerCubit>(context).start();
  279. setState(() {
  280. _isStartPressed = false;
  281. });
  282. },
  283. initialSpeed: kInitialSpeed,
  284. ),
  285. ],
  286. ),
  287. ],
  288. ),
  289. ],
  290. ),
  291. ],
  292. ),
  293. ),
  294. ),
  295. ),
  296. );
  297. }
  298. void _finishTime() {
  299. if (!_puzzleSolved) {
  300. Future.delayed(const Duration(milliseconds: 1500), () {
  301. Navigator.push(context, MaterialPageRoute(
  302. builder: (context) {
  303. return LoseScreen(tiles: _tiles, move: _moves);
  304. },
  305. )).then((value) {
  306. if (value == true) {
  307. BlocProvider.of<CountDownTimerCubit>(context).reset();
  308. BlocProvider.of<CountDownTimerCubit>(context).start();
  309. } else {
  310. Navigator.pop(context);
  311. }
  312. });
  313. });
  314. }
  315. }
  316. void _resetTimer() {
  317. BlocProvider.of<CountDownTimerCubit>(context).reset();
  318. }
  319. }