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.

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