diff --git a/lib/application/notifiers/puzzle_notifier.dart b/lib/application/notifiers/puzzle_notifier.dart index 29c6d05..00ce392 100644 --- a/lib/application/notifiers/puzzle_notifier.dart +++ b/lib/application/notifiers/puzzle_notifier.dart @@ -131,32 +131,28 @@ class PuzzleNotifier extends StateNotifier { int currentTileCol = index % _puzzleSize; //current element moves up - if ((currentTileRow - 1 == emptyTilePosRow) && - (currentTileCol == emptyTilePosCol)) { + if ((currentTileRow - 1 == emptyTilePosRow) && (currentTileCol == emptyTilePosCol)) { board1D[emptyTilePosIndex] = board1D[index]; board1D[index] = 0; _moves++; } //current element moves down - else if ((currentTileRow + 1 == emptyTilePosRow) && - (currentTileCol == emptyTilePosCol)) { + else if ((currentTileRow + 1 == emptyTilePosRow) && (currentTileCol == emptyTilePosCol)) { board1D[emptyTilePosIndex] = board1D[index]; board1D[index] = 0; _moves++; } //current element moves left - else if ((currentTileRow == emptyTilePosRow) && - (currentTileCol + 1 == emptyTilePosCol)) { + else if ((currentTileRow == emptyTilePosRow) && (currentTileCol + 1 == emptyTilePosCol)) { board1D[emptyTilePosIndex] = board1D[index]; board1D[index] = 0; _moves++; } //current element moves right - else if ((currentTileRow == emptyTilePosRow) && - (currentTileCol - 1 == emptyTilePosCol)) { + else if ((currentTileRow == emptyTilePosRow) && (currentTileCol - 1 == emptyTilePosCol)) { board1D[emptyTilePosIndex] = board1D[index]; board1D[index] = 0; _moves++; @@ -172,8 +168,7 @@ class PuzzleNotifier extends StateNotifier { int i = low; while (i < high) { - board1D[(i * _puzzleSize) + emptyTilePosCol] = - board1D[(((i + 1) * _puzzleSize) + emptyTilePosCol)]; + board1D[(i * _puzzleSize) + emptyTilePosCol] = board1D[(((i + 1) * _puzzleSize) + emptyTilePosCol)]; i += 1; } @@ -189,8 +184,7 @@ class PuzzleNotifier extends StateNotifier { int i = low; while (i > high) { - board1D[(i * _puzzleSize) + emptyTilePosCol] = - board1D[(((i - 1) * _puzzleSize) + emptyTilePosCol)]; + board1D[(i * _puzzleSize) + emptyTilePosCol] = board1D[(((i - 1) * _puzzleSize) + emptyTilePosCol)]; i -= 1; } @@ -212,8 +206,7 @@ class PuzzleNotifier extends StateNotifier { int i = low; while (i < high) { - board1D[(emptyTilePosRow * _puzzleSize) + i] = - board1D[(emptyTilePosRow * _puzzleSize) + (i + 1)]; + board1D[(emptyTilePosRow * _puzzleSize) + i] = board1D[(emptyTilePosRow * _puzzleSize) + (i + 1)]; i += 1; } @@ -229,8 +222,7 @@ class PuzzleNotifier extends StateNotifier { int i = low; while (i > high) { - board1D[(i + (emptyTilePosRow * _puzzleSize))] = - board1D[(i - 1) + (emptyTilePosRow * _puzzleSize)]; + board1D[(i + (emptyTilePosRow * _puzzleSize))] = board1D[(i - 1) + (emptyTilePosRow * _puzzleSize)]; i -= 1; } @@ -258,9 +250,6 @@ class PuzzleNotifier extends StateNotifier { if (listEquals(board1D, _solvedList)) { state = PuzzleState.solved(updatedData); } - - log('List: $board1D'); - log('-----------------------'); } int calculateCorrectTiles({required List board}) { diff --git a/lib/application/states/puzzle_state.dart b/lib/application/states/puzzle_state.dart index 590b2b5..bf65356 100644 --- a/lib/application/states/puzzle_state.dart +++ b/lib/application/states/puzzle_state.dart @@ -6,11 +6,18 @@ part 'puzzle_state.freezed.dart'; @freezed class PuzzleState with _$PuzzleState { const factory PuzzleState() = PuzzleIdle; + const factory PuzzleState.initializing() = PuzzleInitializing; + const factory PuzzleState.scrambling(PuzzleData puzzleData) = PuzzleScrambling; + const factory PuzzleState.current(PuzzleData puzzleData) = PuzzleCurrent; + const factory PuzzleState.computingSolution(PuzzleData puzzleData) = PuzzleComputingSolution; + const factory PuzzleState.autoSolving(PuzzleData puzzleData) = PuzzleAutoSolving; + const factory PuzzleState.solved(PuzzleData puzzleData) = PuzzleSolved; + const factory PuzzleState.error({String? message}) = PuzzleError; -} \ No newline at end of file +} diff --git a/lib/application/states/puzzle_state.freezed.dart b/lib/application/states/puzzle_state.freezed.dart index add9b6e..d1e1fb7 100644 --- a/lib/application/states/puzzle_state.freezed.dart +++ b/lib/application/states/puzzle_state.freezed.dart @@ -80,6 +80,7 @@ mixin _$PuzzleState { required TResult Function(String? message) error, }) => throw _privateConstructorUsedError; + @optionalTypeArgs TResult? whenOrNull( TResult Function()? $default, { @@ -105,6 +106,7 @@ mixin _$PuzzleState { required TResult orElse(), }) => throw _privateConstructorUsedError; + @optionalTypeArgs TResult map( TResult Function(PuzzleIdle value) $default, { @@ -117,6 +119,7 @@ mixin _$PuzzleState { required TResult Function(PuzzleError value) error, }) => throw _privateConstructorUsedError; + @optionalTypeArgs TResult? mapOrNull( TResult Function(PuzzleIdle value)? $default, { @@ -146,9 +149,7 @@ mixin _$PuzzleState { /// @nodoc abstract class $PuzzleStateCopyWith<$Res> { - factory $PuzzleStateCopyWith( - PuzzleState value, $Res Function(PuzzleState) then) = - _$PuzzleStateCopyWithImpl<$Res>; + factory $PuzzleStateCopyWith(PuzzleState value, $Res Function(PuzzleState) then) = _$PuzzleStateCopyWithImpl<$Res>; } /// @nodoc @@ -156,20 +157,18 @@ class _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleStateCopyWith<$Res> { _$PuzzleStateCopyWithImpl(this._value, this._then); final PuzzleState _value; + // ignore: unused_field final $Res Function(PuzzleState) _then; } /// @nodoc abstract class $PuzzleIdleCopyWith<$Res> { - factory $PuzzleIdleCopyWith( - PuzzleIdle value, $Res Function(PuzzleIdle) then) = - _$PuzzleIdleCopyWithImpl<$Res>; + factory $PuzzleIdleCopyWith(PuzzleIdle value, $Res Function(PuzzleIdle) then) = _$PuzzleIdleCopyWithImpl<$Res>; } /// @nodoc -class _$PuzzleIdleCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> - implements $PuzzleIdleCopyWith<$Res> { +class _$PuzzleIdleCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleIdleCopyWith<$Res> { _$PuzzleIdleCopyWithImpl(PuzzleIdle _value, $Res Function(PuzzleIdle) _then) : super(_value, (v) => _then(v as PuzzleIdle)); @@ -189,8 +188,7 @@ class _$PuzzleIdle implements PuzzleIdle { @override bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is PuzzleIdle); + return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleIdle); } @override @@ -301,17 +299,14 @@ abstract class PuzzleIdle implements PuzzleState { /// @nodoc abstract class $PuzzleInitializingCopyWith<$Res> { - factory $PuzzleInitializingCopyWith( - PuzzleInitializing value, $Res Function(PuzzleInitializing) then) = + factory $PuzzleInitializingCopyWith(PuzzleInitializing value, $Res Function(PuzzleInitializing) then) = _$PuzzleInitializingCopyWithImpl<$Res>; } /// @nodoc -class _$PuzzleInitializingCopyWithImpl<$Res> - extends _$PuzzleStateCopyWithImpl<$Res> +class _$PuzzleInitializingCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleInitializingCopyWith<$Res> { - _$PuzzleInitializingCopyWithImpl( - PuzzleInitializing _value, $Res Function(PuzzleInitializing) _then) + _$PuzzleInitializingCopyWithImpl(PuzzleInitializing _value, $Res Function(PuzzleInitializing) _then) : super(_value, (v) => _then(v as PuzzleInitializing)); @override @@ -330,8 +325,7 @@ class _$PuzzleInitializing implements PuzzleInitializing { @override bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is PuzzleInitializing); + return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleInitializing); } @override @@ -442,18 +436,16 @@ abstract class PuzzleInitializing implements PuzzleState { /// @nodoc abstract class $PuzzleScramblingCopyWith<$Res> { - factory $PuzzleScramblingCopyWith( - PuzzleScrambling value, $Res Function(PuzzleScrambling) then) = + factory $PuzzleScramblingCopyWith(PuzzleScrambling value, $Res Function(PuzzleScrambling) then) = _$PuzzleScramblingCopyWithImpl<$Res>; + $Res call({PuzzleData puzzleData}); } /// @nodoc -class _$PuzzleScramblingCopyWithImpl<$Res> - extends _$PuzzleStateCopyWithImpl<$Res> +class _$PuzzleScramblingCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleScramblingCopyWith<$Res> { - _$PuzzleScramblingCopyWithImpl( - PuzzleScrambling _value, $Res Function(PuzzleScrambling) _then) + _$PuzzleScramblingCopyWithImpl(PuzzleScrambling _value, $Res Function(PuzzleScrambling) _then) : super(_value, (v) => _then(v as PuzzleScrambling)); @override @@ -490,13 +482,11 @@ class _$PuzzleScrambling implements PuzzleScrambling { return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleScrambling && - const DeepCollectionEquality() - .equals(other.puzzleData, puzzleData)); + const DeepCollectionEquality().equals(other.puzzleData, puzzleData)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); @JsonKey(ignore: true) @override @@ -606,24 +596,23 @@ abstract class PuzzleScrambling implements PuzzleState { const factory PuzzleScrambling(PuzzleData puzzleData) = _$PuzzleScrambling; PuzzleData get puzzleData; + @JsonKey(ignore: true) - $PuzzleScramblingCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleScramblingCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class $PuzzleCurrentCopyWith<$Res> { - factory $PuzzleCurrentCopyWith( - PuzzleCurrent value, $Res Function(PuzzleCurrent) then) = + factory $PuzzleCurrentCopyWith(PuzzleCurrent value, $Res Function(PuzzleCurrent) then) = _$PuzzleCurrentCopyWithImpl<$Res>; + $Res call({PuzzleData puzzleData}); } /// @nodoc class _$PuzzleCurrentCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleCurrentCopyWith<$Res> { - _$PuzzleCurrentCopyWithImpl( - PuzzleCurrent _value, $Res Function(PuzzleCurrent) _then) + _$PuzzleCurrentCopyWithImpl(PuzzleCurrent _value, $Res Function(PuzzleCurrent) _then) : super(_value, (v) => _then(v as PuzzleCurrent)); @override @@ -660,18 +649,15 @@ class _$PuzzleCurrent implements PuzzleCurrent { return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleCurrent && - const DeepCollectionEquality() - .equals(other.puzzleData, puzzleData)); + const DeepCollectionEquality().equals(other.puzzleData, puzzleData)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); @JsonKey(ignore: true) @override - $PuzzleCurrentCopyWith get copyWith => - _$PuzzleCurrentCopyWithImpl(this, _$identity); + $PuzzleCurrentCopyWith get copyWith => _$PuzzleCurrentCopyWithImpl(this, _$identity); @override @optionalTypeArgs @@ -776,25 +762,23 @@ abstract class PuzzleCurrent implements PuzzleState { const factory PuzzleCurrent(PuzzleData puzzleData) = _$PuzzleCurrent; PuzzleData get puzzleData; + @JsonKey(ignore: true) - $PuzzleCurrentCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleCurrentCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class $PuzzleComputingSolutionCopyWith<$Res> { - factory $PuzzleComputingSolutionCopyWith(PuzzleComputingSolution value, - $Res Function(PuzzleComputingSolution) then) = + factory $PuzzleComputingSolutionCopyWith(PuzzleComputingSolution value, $Res Function(PuzzleComputingSolution) then) = _$PuzzleComputingSolutionCopyWithImpl<$Res>; + $Res call({PuzzleData puzzleData}); } /// @nodoc -class _$PuzzleComputingSolutionCopyWithImpl<$Res> - extends _$PuzzleStateCopyWithImpl<$Res> +class _$PuzzleComputingSolutionCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleComputingSolutionCopyWith<$Res> { - _$PuzzleComputingSolutionCopyWithImpl(PuzzleComputingSolution _value, - $Res Function(PuzzleComputingSolution) _then) + _$PuzzleComputingSolutionCopyWithImpl(PuzzleComputingSolution _value, $Res Function(PuzzleComputingSolution) _then) : super(_value, (v) => _then(v as PuzzleComputingSolution)); @override @@ -831,19 +815,16 @@ class _$PuzzleComputingSolution implements PuzzleComputingSolution { return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleComputingSolution && - const DeepCollectionEquality() - .equals(other.puzzleData, puzzleData)); + const DeepCollectionEquality().equals(other.puzzleData, puzzleData)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); @JsonKey(ignore: true) @override $PuzzleComputingSolutionCopyWith get copyWith => - _$PuzzleComputingSolutionCopyWithImpl( - this, _$identity); + _$PuzzleComputingSolutionCopyWithImpl(this, _$identity); @override @optionalTypeArgs @@ -945,29 +926,26 @@ class _$PuzzleComputingSolution implements PuzzleComputingSolution { } abstract class PuzzleComputingSolution implements PuzzleState { - const factory PuzzleComputingSolution(PuzzleData puzzleData) = - _$PuzzleComputingSolution; + const factory PuzzleComputingSolution(PuzzleData puzzleData) = _$PuzzleComputingSolution; PuzzleData get puzzleData; + @JsonKey(ignore: true) - $PuzzleComputingSolutionCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleComputingSolutionCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class $PuzzleAutoSolvingCopyWith<$Res> { - factory $PuzzleAutoSolvingCopyWith( - PuzzleAutoSolving value, $Res Function(PuzzleAutoSolving) then) = + factory $PuzzleAutoSolvingCopyWith(PuzzleAutoSolving value, $Res Function(PuzzleAutoSolving) then) = _$PuzzleAutoSolvingCopyWithImpl<$Res>; + $Res call({PuzzleData puzzleData}); } /// @nodoc -class _$PuzzleAutoSolvingCopyWithImpl<$Res> - extends _$PuzzleStateCopyWithImpl<$Res> +class _$PuzzleAutoSolvingCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleAutoSolvingCopyWith<$Res> { - _$PuzzleAutoSolvingCopyWithImpl( - PuzzleAutoSolving _value, $Res Function(PuzzleAutoSolving) _then) + _$PuzzleAutoSolvingCopyWithImpl(PuzzleAutoSolving _value, $Res Function(PuzzleAutoSolving) _then) : super(_value, (v) => _then(v as PuzzleAutoSolving)); @override @@ -1004,13 +982,11 @@ class _$PuzzleAutoSolving implements PuzzleAutoSolving { return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleAutoSolving && - const DeepCollectionEquality() - .equals(other.puzzleData, puzzleData)); + const DeepCollectionEquality().equals(other.puzzleData, puzzleData)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); @JsonKey(ignore: true) @override @@ -1120,24 +1096,22 @@ abstract class PuzzleAutoSolving implements PuzzleState { const factory PuzzleAutoSolving(PuzzleData puzzleData) = _$PuzzleAutoSolving; PuzzleData get puzzleData; + @JsonKey(ignore: true) - $PuzzleAutoSolvingCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleAutoSolvingCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class $PuzzleSolvedCopyWith<$Res> { - factory $PuzzleSolvedCopyWith( - PuzzleSolved value, $Res Function(PuzzleSolved) then) = + factory $PuzzleSolvedCopyWith(PuzzleSolved value, $Res Function(PuzzleSolved) then) = _$PuzzleSolvedCopyWithImpl<$Res>; + $Res call({PuzzleData puzzleData}); } /// @nodoc -class _$PuzzleSolvedCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> - implements $PuzzleSolvedCopyWith<$Res> { - _$PuzzleSolvedCopyWithImpl( - PuzzleSolved _value, $Res Function(PuzzleSolved) _then) +class _$PuzzleSolvedCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleSolvedCopyWith<$Res> { + _$PuzzleSolvedCopyWithImpl(PuzzleSolved _value, $Res Function(PuzzleSolved) _then) : super(_value, (v) => _then(v as PuzzleSolved)); @override @@ -1174,18 +1148,15 @@ class _$PuzzleSolved implements PuzzleSolved { return identical(this, other) || (other.runtimeType == runtimeType && other is PuzzleSolved && - const DeepCollectionEquality() - .equals(other.puzzleData, puzzleData)); + const DeepCollectionEquality().equals(other.puzzleData, puzzleData)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(puzzleData)); @JsonKey(ignore: true) @override - $PuzzleSolvedCopyWith get copyWith => - _$PuzzleSolvedCopyWithImpl(this, _$identity); + $PuzzleSolvedCopyWith get copyWith => _$PuzzleSolvedCopyWithImpl(this, _$identity); @override @optionalTypeArgs @@ -1290,24 +1261,21 @@ abstract class PuzzleSolved implements PuzzleState { const factory PuzzleSolved(PuzzleData puzzleData) = _$PuzzleSolved; PuzzleData get puzzleData; + @JsonKey(ignore: true) - $PuzzleSolvedCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleSolvedCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc abstract class $PuzzleErrorCopyWith<$Res> { - factory $PuzzleErrorCopyWith( - PuzzleError value, $Res Function(PuzzleError) then) = - _$PuzzleErrorCopyWithImpl<$Res>; + factory $PuzzleErrorCopyWith(PuzzleError value, $Res Function(PuzzleError) then) = _$PuzzleErrorCopyWithImpl<$Res>; + $Res call({String? message}); } /// @nodoc -class _$PuzzleErrorCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> - implements $PuzzleErrorCopyWith<$Res> { - _$PuzzleErrorCopyWithImpl( - PuzzleError _value, $Res Function(PuzzleError) _then) +class _$PuzzleErrorCopyWithImpl<$Res> extends _$PuzzleStateCopyWithImpl<$Res> implements $PuzzleErrorCopyWith<$Res> { + _$PuzzleErrorCopyWithImpl(PuzzleError _value, $Res Function(PuzzleError) _then) : super(_value, (v) => _then(v as PuzzleError)); @override @@ -1348,13 +1316,11 @@ class _$PuzzleError implements PuzzleError { } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(message)); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(message)); @JsonKey(ignore: true) @override - $PuzzleErrorCopyWith get copyWith => - _$PuzzleErrorCopyWithImpl(this, _$identity); + $PuzzleErrorCopyWith get copyWith => _$PuzzleErrorCopyWithImpl(this, _$identity); @override @optionalTypeArgs @@ -1459,7 +1425,7 @@ abstract class PuzzleError implements PuzzleState { const factory PuzzleError({String? message}) = _$PuzzleError; String? get message; + @JsonKey(ignore: true) - $PuzzleErrorCopyWith get copyWith => - throw _privateConstructorUsedError; + $PuzzleErrorCopyWith get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/screens/photo/photo_screen.dart b/lib/screens/photo/photo_screen.dart index 9fffe65..ca2e06a 100644 --- a/lib/screens/photo/photo_screen.dart +++ b/lib/screens/photo/photo_screen.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_flutter_puzzle/application/states/image_splitter_state.dart'; import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; +import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart'; import 'package:my_flutter_puzzle/models/puzzle_data.dart'; import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/res/palette.dart'; @@ -16,11 +18,13 @@ class PhotoScreen extends ConsumerStatefulWidget { required this.initialPuzzleData, required this.puzzleSize, required this.riveController, + required this.duration, Key? key, }) : super(key: key); final PuzzleSolverClient solverClient; final PuzzleData initialPuzzleData; + final int duration; final int puzzleSize; final RiveAnimationController riveController; @@ -48,7 +52,7 @@ class _PhotoScreenState extends ConsumerState { Widget build(BuildContext context) { ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { if (next is PuzzleSolved) { - ref.read(timerNotifierProvider.notifier).stopTimer(); + BlocProvider.of(context).stop(); } }); @@ -85,6 +89,7 @@ class _PhotoScreenState extends ConsumerState { child: PhotoScreenLarge( solverClient: _solverClient, initialPuzzleData: _initialPuzzleData, + duration: widget.duration, puzzleSize: _puzzleSize, riveController: _riveController, ), @@ -113,6 +118,7 @@ class _PhotoScreenState extends ConsumerState { initialPuzzleData: _initialPuzzleData, puzzleSize: _puzzleSize, riveController: _riveController, + duration: widget.duration, ), ); }, @@ -121,6 +127,7 @@ class _PhotoScreenState extends ConsumerState { child: PhotoScreenLarge( solverClient: _solverClient, initialPuzzleData: _initialPuzzleData, + duration: widget.duration, puzzleSize: _puzzleSize, riveController: _riveController, ), diff --git a/lib/screens/photo/photo_screen_large.dart b/lib/screens/photo/photo_screen_large.dart index 9e03078..03d4899 100644 --- a/lib/screens/photo/photo_screen_large.dart +++ b/lib/screens/photo/photo_screen_large.dart @@ -9,6 +9,7 @@ import 'package:my_flutter_puzzle/models/puzzle_data.dart'; import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; +import 'package:my_flutter_puzzle/utils/utils.dart'; import 'package:my_flutter_puzzle/widgets/photo_screen/image_viewer.dart'; import 'package:my_flutter_puzzle/widgets/solo_screen/count_down_timer_widget.dart'; import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; @@ -21,12 +22,14 @@ class PhotoScreenLarge extends ConsumerStatefulWidget { required this.initialPuzzleData, required this.puzzleSize, required this.riveController, + required this.duration, Key? key, }) : super(key: key); final PuzzleSolverClient solverClient; final PuzzleData initialPuzzleData; final int puzzleSize; + final int duration; final RiveAnimationController riveController; @override @@ -38,7 +41,7 @@ class _SoloScreenLargeState extends ConsumerState { late final int _puzzleSize; late final PuzzleData _initialPuzzleData; late final RiveAnimationController _riveController; - + bool _puzzleSolved = false; bool _isStartPressed = false; final _imagePicker = ImagePicker(); final double _fontSize = 70.0; @@ -67,6 +70,9 @@ class _SoloScreenLargeState extends ConsumerState { _isStartPressed = true; }); } + if (next is PuzzleSolved) { + _puzzleSolved = true; + } }); ref.listen(imageSplitterNotifierProvider, (previous, next) { @@ -79,124 +85,136 @@ class _SoloScreenLargeState extends ConsumerState { } }); - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - body: SafeArea( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 32), - MovesTilesWidget(solverClient: _solverClient, fontSize: 16), - const SizedBox(height: 32), - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - ), - ], + return WillPopScope( + onWillPop: () async { + BlocProvider.of(context).stop(); + return true; + }, + child: Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, + body: SafeArea( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsetsDirectional.symmetric(horizontal: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 32), + MovesTilesWidget(solverClient: _solverClient, fontSize: 16), + const SizedBox(height: 32), + GameButtonWidget( + solverClient: _solverClient, + initialPuzzleData: _initialPuzzleData, + ), + ], + ), ), - ), - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - // const TimerWidget(fontSize: 30), - CountDownTimerWidget( - duration: 3, - finishCallback: () {}, - ), - const SizedBox(height: 12), - Consumer( - builder: (context, ref, child) { - final state = ref.watch(imageSplitterNotifierProvider); + SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CountDownTimerWidget( + duration: widget.duration, + finishCallback: () { + if (!_puzzleSolved) { + Utils.instance.showToast(context, 'TimeOut'); + Future.delayed(const Duration(milliseconds: 1500), () { + Navigator.pop(context); + }); + } + }, + ), + const SizedBox(height: 12), + Consumer( + builder: (context, ref, child) { + final state = ref.watch(imageSplitterNotifierProvider); - return state.maybeWhen( - () => PuzzleWidget( - solverClient: _solverClient, - boardSize: _boardSize, - eachBoxSize: _eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: _fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - ), - complete: (image, images, palette) { - _previousImages = images; - _previousImage = image; - _previousPalette = palette; + return state.maybeWhen( + () => PuzzleWidget( + solverClient: _solverClient, + boardSize: _boardSize, + eachBoxSize: _eachBoxSize, + initialPuzzleData: _initialPuzzleData, + fontSize: _fontSize, + images: _previousImages, + kInitialSpeed: kInitialSpeed, + ), + complete: (image, images, palette) { + _previousImages = images; + _previousImage = image; + _previousPalette = palette; - return PuzzleWidget( + return PuzzleWidget( + solverClient: _solverClient, + boardSize: _boardSize, + eachBoxSize: _eachBoxSize, + initialPuzzleData: _initialPuzzleData, + fontSize: _fontSize, + images: images, + kInitialSpeed: kInitialSpeed, + ); + }, + orElse: () => PuzzleWidget( solverClient: _solverClient, boardSize: _boardSize, eachBoxSize: _eachBoxSize, initialPuzzleData: _initialPuzzleData, fontSize: _fontSize, - images: images, + images: _previousImages, kInitialSpeed: kInitialSpeed, - ); - }, - orElse: () => PuzzleWidget( - solverClient: _solverClient, - boardSize: _boardSize, - eachBoxSize: _eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: _fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - ), - ); - }, - ), - const SizedBox(height: 30), - ], + ), + ); + }, + ), + const SizedBox(height: 30), + ], + ), ), - ), - Padding( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 10), - child: Stack( - children: [ - AnimatedDash( - boardSize: _boardSize * 0.8, - riveController: _riveController, - onInit: (_) => setState(() {}), - ), - Column( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CountdownWidget( - isStartPressed: _isStartPressed, - onFinish: () { - // ref.read(timerNotifierProvider.notifier).startTimer(); - BlocProvider.of(context).start(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - Visibility( - visible: !_isStartPressed, - child: ImageViewer( - imagePicker: _imagePicker, - puzzleSize: _puzzleSize, - previousImage: _previousImage, - previousPalette: _previousPalette, - imageSize: 200, + Padding( + padding: const EdgeInsetsDirectional.symmetric(horizontal: 10), + child: Stack( + children: [ + AnimatedDash( + boardSize: _boardSize * 0.8, + riveController: _riveController, + onInit: (_) => setState(() {}), + ), + Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CountdownWidget( + isStartPressed: _isStartPressed, + onFinish: () { + // ref.read(timerNotifierProvider.notifier).startTimer(); + BlocProvider.of(context).start(); + setState(() { + _isStartPressed = false; + }); + }, + initialSpeed: kInitialSpeed, + ), + Visibility( + visible: !_isStartPressed, + child: ImageViewer( + imagePicker: _imagePicker, + puzzleSize: _puzzleSize, + previousImage: _previousImage, + previousPalette: _previousPalette, + imageSize: 200, + ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/screens/photo/photo_screen_medium.dart b/lib/screens/photo/photo_screen_medium.dart deleted file mode 100644 index 9a74847..0000000 --- a/lib/screens/photo/photo_screen_medium.dart +++ /dev/null @@ -1,200 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:my_flutter_puzzle/application/states/image_splitter_state.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/models/puzzle_data.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/res/palette.dart'; -import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; -import 'package:my_flutter_puzzle/utils/color_brightness.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/widgets/photo_screen/image_viewer.dart'; -import 'package:my_flutter_puzzle/widgets/photo_screen/pick_image_button.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/countdown_overlay.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; -import 'package:palette_generator/palette_generator.dart'; -import 'package:rive/rive.dart'; - -class PhotoScreenMedium extends ConsumerStatefulWidget { - const PhotoScreenMedium({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final RiveAnimationController riveController; - - @override - ConsumerState createState() => _PhotoScreenMediumState(); -} - -class _PhotoScreenMediumState extends ConsumerState { - late final PuzzleSolverClient _solverClient; - late final int _puzzleSize; - late final PuzzleData _initialPuzzleData; - late final RiveAnimationController _riveController; - bool _isStartPressed = false; - - final _imagePicker = ImagePicker(); - - List? _previousImages; - Image? _previousImage; - PaletteGenerator? _previousPalette; - - @override - void initState() { - _solverClient = widget.solverClient; - _puzzleSize = widget.puzzleSize; - _initialPuzzleData = widget.initialPuzzleData; - _riveController = widget.riveController; - super.initState(); - } - - @override - Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleSolved) {} - if (next is PuzzleInitializing) { - setState(() { - _isStartPressed = true; - }); - } - }); - - ref.listen(imageSplitterNotifierProvider, (previous, next) { - if (next is ImageSplitterComplete) { - setState(() { - _previousImages = next.images; - _previousImage = next.image; - _previousPalette = next.palette; - }); - } - }); - - var fontSize = 64.0; - var boardSize = 400.0; - - var spacing = 5; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Stack( - children: [ - Scaffold( - backgroundColor: Palette.blue.darken(0.3), - body: Stack( - children: [ - Row( - children: [ - const Spacer(), - AnimatedDash( - boardSize: boardSize / 1.5, - riveController: _riveController, - onInit: (_) => setState(() {}), - ), - ], - ), - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(), - const SizedBox(height: 16), - MovesTilesWidget(solverClient: _solverClient), - const SizedBox(height: 16), - const TimerWidget(fontSize: 36), - const SizedBox(height: 36), - Consumer( - builder: (context, ref, child) { - final state = ref.watch(imageSplitterNotifierProvider); - return state.maybeWhen( - () => PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - ), - complete: (image, images, palette) { - _previousImages = images; - _previousImage = image; - _previousPalette = palette; - - return PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: images, - kInitialSpeed: kInitialSpeed, - ); - }, - orElse: () => PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - ), - ); - }, - ), - const SizedBox(height: 36), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - ), - const SizedBox(width: 36), - PickImageButton( - text: 'Pick Image', - onTap: ref.read(imageSplitterNotifierProvider) is ImageSplitterComplete - ? () => ref.read(imageSplitterNotifierProvider.notifier).generateImages( - picker: _imagePicker, - puzzleSize: _puzzleSize, - ) - : null, - ), - ], - ), - const SizedBox(height: 36), - ImageViewer( - imagePicker: _imagePicker, - puzzleSize: _puzzleSize, - previousImage: _previousImage, - previousPalette: _previousPalette, - imageSize: 150, - ), - ], - ), - ), - ], - ), - ), - CountdownOverlay( - isStartPressed: _isStartPressed, - onFinish: () { - ref.read(timerNotifierProvider.notifier).startTimer(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - ], - ); - } -} diff --git a/lib/screens/photo/photo_screen_small.dart b/lib/screens/photo/photo_screen_small.dart deleted file mode 100644 index 7d49927..0000000 --- a/lib/screens/photo/photo_screen_small.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:my_flutter_puzzle/application/states/image_splitter_state.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/models/puzzle_data.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/widgets/photo_screen/image_viewer.dart'; -import 'package:my_flutter_puzzle/widgets/photo_screen/pick_image_button.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/countdown_overlay.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; -import 'package:palette_generator/palette_generator.dart'; -import 'package:rive/rive.dart'; - -class PhotoScreenSmall extends ConsumerStatefulWidget { - const PhotoScreenSmall({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final RiveAnimationController riveController; - - @override - ConsumerState createState() => _SoloScreenLargeState(); -} - -class _SoloScreenLargeState extends ConsumerState { - late final PuzzleSolverClient _solverClient; - late final int _puzzleSize; - late final PuzzleData _initialPuzzleData; - late final RiveAnimationController _riveController; - bool _isStartPressed = false; - - final _imagePicker = ImagePicker(); - - List? _previousImages; - Image? _previousImage; - PaletteGenerator? _previousPalette; - - @override - void initState() { - _solverClient = widget.solverClient; - _puzzleSize = widget.puzzleSize; - _initialPuzzleData = widget.initialPuzzleData; - _riveController = widget.riveController; - super.initState(); - } - - @override - Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleInitializing) { - setState(() { - _isStartPressed = true; - }); - } - }); - - ref.listen(imageSplitterNotifierProvider, (previous, next) { - if (next is ImageSplitterComplete) { - setState(() { - _previousImages = next.images; - _previousImage = next.image; - _previousPalette = next.palette; - }); - } - }); - - var fontSize = 48.0; - var boardSize = 300.0; - - var spacing = 2; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Stack( - children: [ - Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - // appBar: PreferredSize( - // child: Container( - // color: Theme.of(context).colorScheme.background, - // ), - // preferredSize: const Size(double.maxFinite, 30), - // ), - body: Stack( - children: [ - Row( - children: [ - const Spacer(), - AnimatedDash( - boardSize: boardSize / 1.6, - riveController: _riveController, - onInit: (_) => setState(() {}), - padding: const EdgeInsets.only(right: 16.0, bottom: 30), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row(), - const SizedBox(height: 60), - MovesTilesWidget( - solverClient: _solverClient, - fontSize: 22, - ), - const SizedBox(height: 20), - const TimerWidget(fontSize: 24), - const SizedBox(height: 60), - Consumer( - builder: (context, ref, child) { - final state = ref.watch(imageSplitterNotifierProvider); - return state.maybeWhen( - () => PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - borderRadius: 16, - ), - complete: (image, images, palette) { - _previousImages = images; - _previousImage = image; - _previousPalette = palette; - - return PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: images, - kInitialSpeed: kInitialSpeed, - borderRadius: 16, - ); - }, - orElse: () => PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - images: _previousImages, - kInitialSpeed: kInitialSpeed, - borderRadius: 16, - ), - ); - }, - ), - const SizedBox(height: 24), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - padding: const EdgeInsets.only(top: 10.0, bottom: 9.0), - width: 130, - ), - const SizedBox(width: 16), - PickImageButton( - text: 'Pick Image', - onTap: ref.read(imageSplitterNotifierProvider) is ImageSplitterComplete - ? () => ref.read(imageSplitterNotifierProvider.notifier).generateImages( - picker: _imagePicker, - puzzleSize: _puzzleSize, - ) - : null, - padding: const EdgeInsets.only(top: 10.0, bottom: 9.0), - width: 130, - ), - ], - ), - const SizedBox(height: 16), - ImageViewer( - imagePicker: _imagePicker, - puzzleSize: _puzzleSize, - previousImage: _previousImage, - previousPalette: _previousPalette, - imageSize: 110, - ), - const SizedBox(height: 50), - ], - ), - ], - ), - ), - CountdownOverlay( - isStartPressed: _isStartPressed, - onFinish: () { - ref.read(timerNotifierProvider.notifier).startTimer(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - ], - ); - } -} diff --git a/lib/screens/puzzle/puzzle_screen_large.dart b/lib/screens/puzzle/puzzle_screen_large.dart deleted file mode 100644 index cc8dcc9..0000000 --- a/lib/screens/puzzle/puzzle_screen_large.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/application/notifiers/puzzle_type_notifier.dart'; -import 'package:my_flutter_puzzle/models/puzzle_data.dart'; -import 'package:my_flutter_puzzle/screens/photo/photo_screen_large.dart'; -import 'package:my_flutter_puzzle/screens/solo/solo_screen_large.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:rive/rive.dart'; - -import '../../providers.dart'; - -class PuzzleScreenLarge extends ConsumerWidget { - const PuzzleScreenLarge({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final RiveAnimationController riveController; - - @override - Widget build(BuildContext context, WidgetRef ref) { - final currentPuzzleType = ref.watch(puzzleTypeNotifierProvider); - - final name = currentPuzzleType.name[0].toUpperCase() + currentPuzzleType.name.substring(1); - - switch (currentPuzzleType) { - case PuzzleType.normal: - return SoloScreenLarge( - solverClient: solverClient, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - puzzleType: name, - riveController: riveController, - ); - case PuzzleType.photo: - return PhotoScreenLarge( - solverClient: solverClient, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - riveController: riveController, - ); - case PuzzleType.multiplayer: - default: - return SoloScreenLarge( - solverClient: solverClient, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - puzzleType: name, - riveController: riveController, - ); - } - } -} diff --git a/lib/screens/puzzle/puzzle_starter_screen.dart b/lib/screens/puzzle/puzzle_starter_screen.dart index 739835e..d8bfd7c 100644 --- a/lib/screens/puzzle/puzzle_starter_screen.dart +++ b/lib/screens/puzzle/puzzle_starter_screen.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_flutter_puzzle/application/states/image_splitter_state.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; import 'package:my_flutter_puzzle/models/puzzle_data.dart'; import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/screens/photo/photo_screen.dart'; @@ -36,6 +35,7 @@ class _SoloScreenState extends ConsumerState { _riveController = SimpleAnimation('idle'); _solverClient = PuzzleSolverClient(size: _puzzleSize); _initialPuzzleData = ref.read(puzzleNotifierProvider(_solverClient).notifier).generateInitialPuzzle(); + ref.refresh(imageSplitterNotifierProvider); final state = ref.read(imageSplitterNotifierProvider); if (state is! ImageSplitterComplete) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { @@ -52,16 +52,12 @@ class _SoloScreenState extends ConsumerState { @override Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleSolved) { - ref.read(timerNotifierProvider.notifier).stopTimer(); - } - }); return AnimatedSwitcher( duration: const Duration(milliseconds: 400), child: PhotoScreen( solverClient: _solverClient, initialPuzzleData: _initialPuzzleData, + duration: widget.duration, puzzleSize: _puzzleSize, riveController: _riveController, ), diff --git a/lib/screens/solo/solo_large_screen_prev.dart b/lib/screens/solo/solo_large_screen_prev.dart deleted file mode 100644 index d2cc772..0000000 --- a/lib/screens/solo/solo_large_screen_prev.dart +++ /dev/null @@ -1,635 +0,0 @@ -import 'dart:developer'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:my_flutter_puzzle/res/palette.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:rive/rive.dart'; - -class SoloLargeScreen extends StatefulWidget { - const SoloLargeScreen({ - Key? key, - }) : super(key: key); - - @override - _SoloLargeScreenState createState() => _SoloLargeScreenState(); -} - -class _SoloLargeScreenState extends State { - late PuzzleSolverClient _solverClient; - late RiveAnimationController _riveController; - - List>? _board2D; - List? myList; - int _moves = 0; - final _puzzleSize = 3; - final int _animationSpeedInMilliseconds = 300; - bool _isComputing = false; - bool _isAutoSolving = false; - bool _isSolved = false; - - Map? _offsetMap; - List _solvedList = []; - - @override - void initState() { - super.initState(); - _solverClient = PuzzleSolverClient(size: _puzzleSize); - _riveController = SimpleAnimation('idle'); - initBoard(); - generateSolvedList(); - } - - generateSolvedList() { - for (int i = 1; i < _puzzleSize * _puzzleSize; i++) { - _solvedList.add(i); - } - _solvedList.add(0); - } - - scrambleBoard() { - final generated2DBoard = _solverClient.createRandomBoard(); - final generated1DBoard = _solverClient.convertTo1D(generated2DBoard); - updateOffset(generated1DBoard); - setState(() { - _board2D = generated2DBoard; - myList = generated1DBoard; - _moves = 0; - _isSolved = false; - }); - } - - initBoard() { - final generated2DBoard = _solverClient.createRandomBoard(); - final generated1DBoard = _solverClient.convertTo1D(generated2DBoard); - - createOffset(generated1DBoard); - - setState(() { - _board2D = generated2DBoard; - myList = generated1DBoard; - _moves = 0; - }); - } - - startAutoSolver() async { - if (_board2D != null) { - setState(() { - _isComputing = true; - }); - - List>? boardStates = await compute( - _solverClient.runner, _solverClient.convertTo2D(myList!)); - - setState(() { - _isComputing = false; - _isAutoSolving = true; - }); - - if (boardStates != null) { - for (var board in boardStates) { - await Future.delayed(Duration( - milliseconds: _animationSpeedInMilliseconds, - )); - setState(() { - myList = board; - _moves++; - }); - updateOffset(myList!); - } - } - } - setState(() { - _isAutoSolving = false; - _isSolved = true; - }); - showCompleteDialogBox(context); - } - - isSolved(List currentBoard) { - if (listEquals(currentBoard, _solvedList)) { - setState(() { - _isSolved = true; - }); - return true; - } - setState(() { - _isSolved = false; - }); - - return false; - } - - onClick(index) { - log('-----------------------'); - log('Tapped index: $index'); - - if (myList != null) { - int emptyTilePosIndex = myList!.indexOf(0); - int emptyTilePosRow = emptyTilePosIndex ~/ _puzzleSize; - int emptyTilePosCol = emptyTilePosIndex % _puzzleSize; - - int currentTileRow = index ~/ _puzzleSize; - int currentTileCol = index % _puzzleSize; - - //current element moves up - if ((currentTileRow - 1 == emptyTilePosRow) && - (currentTileCol == emptyTilePosCol)) { - myList![emptyTilePosIndex] = myList![index]; - myList![index] = 0; - _moves++; - } - - //current element moves down - else if ((currentTileRow + 1 == emptyTilePosRow) && - (currentTileCol == emptyTilePosCol)) { - myList![emptyTilePosIndex] = myList![index]; - myList![index] = 0; - _moves++; - } - - //current element moves left - else if ((currentTileRow == emptyTilePosRow) && - (currentTileCol + 1 == emptyTilePosCol)) { - myList![emptyTilePosIndex] = myList![index]; - myList![index] = 0; - _moves++; - } - - //current element moves right - else if ((currentTileRow == emptyTilePosRow) && - (currentTileCol - 1 == emptyTilePosCol)) { - myList![emptyTilePosIndex] = myList![index]; - myList![index] = 0; - _moves++; - } else { - if (currentTileCol == emptyTilePosCol) { - int low; - int high; - - // multiple elements move up - if (emptyTilePosRow < currentTileRow) { - low = emptyTilePosRow; - high = currentTileRow; - - int i = low; - while (i < high) { - myList![(i * _puzzleSize) + emptyTilePosCol] = - myList![(((i + 1) * _puzzleSize) + emptyTilePosCol)]; - - i += 1; - } - - myList![(high * _puzzleSize) + emptyTilePosCol] = 0; - _moves++; - } - - //multiple elements move down - else { - low = emptyTilePosRow; - high = currentTileRow; - - int i = low; - while (i > high) { - myList![(i * _puzzleSize) + emptyTilePosCol] = - myList![(((i - 1) * _puzzleSize) + emptyTilePosCol)]; - - i -= 1; - } - - myList![(high * _puzzleSize) + emptyTilePosCol] = 0; - _moves++; - } - } - - // multiple elements move left or right - if (currentTileRow == emptyTilePosRow) { - int low; - int high; - - // multiple elements move left - if (emptyTilePosCol < currentTileCol) { - low = emptyTilePosCol; - high = currentTileCol; - - int i = low; - while (i < high) { - myList![(emptyTilePosRow * _puzzleSize) + i] = - myList![(emptyTilePosRow * _puzzleSize) + (i + 1)]; - - i += 1; - } - - myList![high + (emptyTilePosRow * _puzzleSize)] = 0; - _moves++; - } - - //multiple elements move right - else { - low = emptyTilePosCol; - high = currentTileCol; - - int i = low; - while (i > high) { - myList![(i + (emptyTilePosRow * _puzzleSize))] = - myList![(i - 1) + (emptyTilePosRow * _puzzleSize)]; - - i -= 1; - } - - myList![high + (emptyTilePosRow * _puzzleSize)] = 0; - _moves++; - } - } - } - - // Update Offset list - // setState(() { - // updateOffset(myList!); - // }); - updateOffset(myList!); - setState(() {}); - - if (isSolved(myList!)) { - showCompleteDialogBox(context); - } - - log('List: $myList'); - log('-----------------------'); - } - } - - createOffset(List board) { - Map offsetMap = {}; - int j = 0; - - log('BOARD: $board'); - - for (int i = 0; i < board.length; i++) { - final xMod = i % _puzzleSize; - double x = xMod / (_puzzleSize - 1); - - if (x % i == 0 && i != 0) j++; - int yMod = j % _puzzleSize; - double y = yMod / (_puzzleSize - 1); - - offsetMap.addEntries([ - MapEntry( - board[i], - FractionalOffset(x, y), - ) - ]); - } - - log('INITIAL OFFSET MAP: $offsetMap'); - setState(() { - _offsetMap = offsetMap; - }); - } - - updateOffset(List board) { - int j = 0; - - for (int i = 0; i < board.length; i++) { - final xMod = i % _puzzleSize; - double x = xMod / (_puzzleSize - 1); - - if (x % i == 0 && i != 0) j++; - int yMod = j % _puzzleSize; - double y = yMod / (_puzzleSize - 1); - - _offsetMap![board[i]] = FractionalOffset(x, y); - } - log('OFFSET MAP: $_offsetMap'); - } - - showCompleteDialogBox(BuildContext context) { - showDialog( - context: context, - builder: (context) => Dialog( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Solved successfully!', - style: TextStyle(fontSize: 22), - ), - const SizedBox(height: 16), - ElevatedButton( - style: ElevatedButton.styleFrom( - primary: Palette.violet, - onSurface: Palette.violet, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Padding( - padding: EdgeInsets.all(16.0), - child: Text( - 'OK', - style: TextStyle(fontSize: 22), - ), - ), - ), - ], - ), - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - var screenSize = MediaQuery.of(context).size; - - var shortestSide = screenSize.shortestSide; - var fontSize = shortestSide * 0.08; - var boardSize = shortestSide * 0.45; - - var spacing = 5; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Scaffold( - backgroundColor: Colors.black, - appBar: PreferredSize( - child: Container( - color: Colors.black, - ), - preferredSize: Size(double.maxFinite, shortestSide * 0.1), - ), - body: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 56.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(), - const Text( - 'Photo', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 8), - const Text( - 'Puzzle', - style: TextStyle( - fontSize: 58, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const Text( - 'Challenge', - style: TextStyle( - fontSize: 58, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 32), - RichText( - text: TextSpan( - style: const TextStyle( - fontSize: 24, - // fontWeight: FontWeight.w500, - color: Colors.white, - ), - children: [ - TextSpan( - text: _moves.toString(), - style: const TextStyle( - fontWeight: FontWeight.w600, - ), - ), - const TextSpan(text: ' Moves | '), - const TextSpan( - text: '15', - style: TextStyle( - fontWeight: FontWeight.w600, - ), - ), - const TextSpan(text: ' Tiles'), - ], - ), - ), - const SizedBox(height: 32), - SizedBox( - width: 145, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30), - ), - ), - onPressed: () {}, - child: const Padding( - padding: EdgeInsets.only(top: 13.0, bottom: 12.0), - child: Text( - 'Start Game', - // 'Restart', - // 'Get ready...', - style: TextStyle( - fontSize: 16, - ), - ), - ), - ), - ), - ], - ), - ), - myList != null && _offsetMap != null - ? Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - // Row(), - // MovesText( - // moves: _moves, - // fontSize: fontSize, - // ), - Row( - mainAxisSize: MainAxisSize.min, - children: const [ - Text( - '00:00:00', - style: TextStyle( - fontSize: 40, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon( - Icons.timer, - color: Colors.white, - size: 40, - ) - ], - ), - SizedBox( - height: boardSize, - width: boardSize, - child: Stack( - children: [ - for (int i = 0; i < _offsetMap!.length; i++) - _offsetMap!.entries.toList()[i].key != 0 - ? AnimatedAlign( - alignment: - _offsetMap!.entries.toList()[i].value, - duration: Duration( - milliseconds: - _animationSpeedInMilliseconds, - ), - curve: Curves.easeInOut, - child: GestureDetector( - onTap: () => onClick(myList!.indexOf( - _offsetMap!.entries.toList()[i].key)), - child: Card( - elevation: 4, - color: const Color(0xFF2868d7), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(20), - ), - child: SizedBox( - height: eachBoxSize, - width: eachBoxSize, - child: Center( - child: Text( - _offsetMap!.entries - .toList()[i] - .key - .toString(), - style: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ), - ), - ), - ) - : const SizedBox(), - ], - ), - ), - const SizedBox(height: 30), - // Row( - // mainAxisSize: MainAxisSize.min, - // children: [ - // Padding( - // padding: const EdgeInsets.only(bottom: 30.0), - // child: SizedBox( - // width: MediaQuery.of(context).size.width * 0.2, - // child: ElevatedButton( - // style: ElevatedButton.styleFrom( - // primary: Palette.violet, - // onSurface: Palette.violet, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(50), - // ), - // ), - // onPressed: _isComputing || _isAutoSolving || _isSolved - // ? null - // : () { - // startAutoSolver(); - // }, - // child: Padding( - // padding: const EdgeInsets.all(16.0), - // child: _isComputing || _isAutoSolving - // ? Row( - // children: [ - // const SizedBox( - // width: 25, - // height: 25, - // child: CircularProgressIndicator( - // color: Palette.violet, - // strokeWidth: 2, - // ), - // ), - // const SizedBox(width: 16), - // Text( - // _isComputing - // ? 'Computing ...' - // : 'Solving ...', - // style: const TextStyle(fontSize: 20), - // ), - // ], - // ) - // : const Text( - // 'Start Auto Solver', - // style: TextStyle(fontSize: 22), - // ), - // ), - // ), - // ), - // ), - // const SizedBox(width: 16.0), - // Padding( - // padding: const EdgeInsets.only(bottom: 30.0), - // child: SizedBox( - // width: MediaQuery.of(context).size.width * 0.2, - // child: ElevatedButton( - // style: ElevatedButton.styleFrom( - // primary: Palette.crimson, - // onSurface: Palette.crimson, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(50), - // ), - // ), - // onPressed: _isComputing || _isAutoSolving - // ? null - // : () { - // scrambleBoard(); - // }, - // child: const Padding( - // padding: EdgeInsets.all(16.0), - // child: Text( - // 'Scramble', - // style: TextStyle(fontSize: 22), - // ), - // ), - // ), - // ), - // ), - // ], - // ), - ], - ) - : const SizedBox(), - Align( - alignment: Alignment.bottomCenter, - child: Padding( - padding: const EdgeInsets.only(right: 56.0, bottom: 56), - child: SizedBox( - width: boardSize * 0.75, - height: boardSize * 0.75, - child: RiveAnimation.asset( - 'assets/rive/dash.riv', - fit: BoxFit.contain, - antialiasing: true, - controllers: [_riveController], - onInit: (_) => setState(() {}), - ), - ), - ), - ), - // SizedBox(), - ], - ), - ); - } -} diff --git a/lib/screens/solo/solo_screen.dart b/lib/screens/solo/solo_screen.dart deleted file mode 100644 index 9540436..0000000 --- a/lib/screens/solo/solo_screen.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/screens/solo/solo_screen_large.dart'; -import 'package:my_flutter_puzzle/screens/solo/solo_screen_small.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/utils/responsive_layout.dart'; -import 'package:rive/rive.dart'; - -import '../../models/puzzle_data.dart'; -import 'solo_screen_medium.dart'; - -class SoloScreen extends ConsumerWidget { - const SoloScreen({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.puzzleType, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final String puzzleType; - final RiveAnimationController riveController; - - @override - Widget build(BuildContext context, WidgetRef ref) { - ref.listen(puzzleNotifierProvider(solverClient), - (previous, PuzzleState next) { - if (next is PuzzleSolved) { - ref.read(timerNotifierProvider.notifier).stopTimer(); - } - }); - - return ResponsiveLayout( - largeChild: SoloScreenLarge( - solverClient: solverClient, - puzzleType: puzzleType, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - riveController: riveController, - ), - mediumChild: SoloScreenMedium( - solverClient: solverClient, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - puzzleType: puzzleType, - riveController: riveController, - ), - smallChild: SoloScreenSmall( - solverClient: solverClient, - initialPuzzleData: initialPuzzleData, - puzzleSize: puzzleSize, - puzzleType: puzzleType, - riveController: riveController, - ), - ); - } -} diff --git a/lib/screens/solo/solo_screen_large.dart b/lib/screens/solo/solo_screen_large.dart deleted file mode 100644 index 86a2e55..0000000 --- a/lib/screens/solo/solo_screen_large.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; -import 'package:my_flutter_puzzle/screens/puzzle/top_bar.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; -import 'package:rive/rive.dart'; - -import '../../models/puzzle_data.dart'; - -class SoloScreenLarge extends ConsumerStatefulWidget { - const SoloScreenLarge({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.puzzleType, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final String puzzleType; - final RiveAnimationController riveController; - - @override - ConsumerState createState() => _SoloScreenLargeState(); -} - -class _SoloScreenLargeState extends ConsumerState { - late final PuzzleSolverClient _solverClient; - late final int _puzzleSize; - late final PuzzleData _initialPuzzleData; - late final String _puzzleType; - late final RiveAnimationController _riveController; - bool _isStartPressed = false; - - @override - void initState() { - _solverClient = widget.solverClient; - _puzzleSize = widget.puzzleSize; - _initialPuzzleData = widget.initialPuzzleData; - _puzzleType = widget.puzzleType; - _riveController = widget.riveController; - super.initState(); - } - - @override - Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleSolved) { - // TODO: Add celebration - } - if (next is PuzzleInitializing) { - setState(() { - _isStartPressed = true; - }); - } - }); - - var fontSize = 70.0; - var boardSize = 450.0; - - var spacing = 5; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Scaffold( - backgroundColor: Theme.of(context).backgroundColor, - body: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 56.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(), - Text( - _puzzleType, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 8), - const Text( - 'Puzzle', - style: TextStyle( - fontSize: 58, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const Text( - 'Challenge', - style: TextStyle( - fontSize: 58, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 32), - MovesTilesWidget(solverClient: _solverClient), - const SizedBox(height: 32), - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - ), - ], - ), - ), - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const TimerWidget( - fontSize: 40, - ), - const SizedBox(height: 36), - PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - kInitialSpeed: kInitialSpeed, - ), - const SizedBox(height: 30), - ], - ), - ), - Column( - mainAxisSize: MainAxisSize.max, - children: [ - const Spacer(), - CountdownWidget( - isStartPressed: _isStartPressed, - onFinish: () { - ref.read(timerNotifierProvider.notifier).startTimer(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - const Spacer(), - AnimatedDash( - boardSize: boardSize * 0.8, - riveController: _riveController, - onInit: (_) => setState(() {}), - ), - ], - ), - // SizedBox(), - ], - ), - ); - } -} diff --git a/lib/screens/solo/solo_screen_medium.dart b/lib/screens/solo/solo_screen_medium.dart deleted file mode 100644 index 629f75f..0000000 --- a/lib/screens/solo/solo_screen_medium.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; -import 'package:my_flutter_puzzle/screens/puzzle/top_bar.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/countdown_overlay.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; -import 'package:rive/rive.dart'; - -import '../../models/puzzle_data.dart'; - -class SoloScreenMedium extends ConsumerStatefulWidget { - const SoloScreenMedium({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.puzzleType, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final String puzzleType; - final RiveAnimationController riveController; - - @override - ConsumerState createState() => _SoloScreenLargeState(); -} - -class _SoloScreenLargeState extends ConsumerState { - late final PuzzleSolverClient _solverClient; - late final int _puzzleSize; - late final PuzzleData _initialPuzzleData; - late final String _puzzleType; - late final RiveAnimationController _riveController; - bool _isStartPressed = false; - - @override - void initState() { - _solverClient = widget.solverClient; - _puzzleSize = widget.puzzleSize; - _initialPuzzleData = widget.initialPuzzleData; - _puzzleType = widget.puzzleType; - _riveController = widget.riveController; - super.initState(); - } - - @override - Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleSolved) { - // TODO: Add celebration - } - if (next is PuzzleInitializing) { - setState(() { - _isStartPressed = true; - }); - } - }); - - var fontSize = 64.0; - var boardSize = 400.0; - - var spacing = 5; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Stack( - children: [ - Scaffold( - backgroundColor: Theme.of(context).backgroundColor, - body: Stack( - children: [ - Row( - children: [ - const Spacer(), - AnimatedDash( - boardSize: boardSize / 1.5, - riveController: _riveController, - onInit: (_) => setState(() {}), - ), - ], - ), - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(), - // Text( - // _puzzleType, - // style: const TextStyle( - // fontSize: 18, - // fontWeight: FontWeight.w500, - // color: Colors.white, - // ), - // ), - const SizedBox(height: 8), - const Text( - 'Puzzle Challenge', - style: TextStyle( - fontSize: 36, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 16), - MovesTilesWidget(solverClient: _solverClient), - const SizedBox(height: 16), - const TimerWidget(fontSize: 36), - const SizedBox(height: 36), - PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - kInitialSpeed: kInitialSpeed, - ), - const SizedBox(height: 36), - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - ), - const SizedBox(height: 100), - ], - ), - ), - ], - ), - ), - CountdownOverlay( - isStartPressed: _isStartPressed, - onFinish: () { - ref.read(timerNotifierProvider.notifier).startTimer(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - ], - ); - } -} diff --git a/lib/screens/solo/solo_screen_small.dart b/lib/screens/solo/solo_screen_small.dart deleted file mode 100644 index 9f3fb80..0000000 --- a/lib/screens/solo/solo_screen_small.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/application/states/puzzle_state.dart'; -import 'package:my_flutter_puzzle/providers.dart'; -import 'package:my_flutter_puzzle/res/puzzle_constants.dart'; -import 'package:my_flutter_puzzle/screens/puzzle/top_bar.dart'; -import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/countdown_overlay.dart'; -import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; -import 'package:rive/rive.dart'; - -import '../../models/puzzle_data.dart'; - -class SoloScreenSmall extends ConsumerStatefulWidget { - const SoloScreenSmall({ - required this.solverClient, - required this.initialPuzzleData, - required this.puzzleSize, - required this.puzzleType, - required this.riveController, - Key? key, - }) : super(key: key); - - final PuzzleSolverClient solverClient; - final PuzzleData initialPuzzleData; - final int puzzleSize; - final String puzzleType; - final RiveAnimationController riveController; - - @override - ConsumerState createState() => _SoloScreenLargeState(); -} - -class _SoloScreenLargeState extends ConsumerState { - late final PuzzleSolverClient _solverClient; - late final int _puzzleSize; - late final PuzzleData _initialPuzzleData; - late final String _puzzleType; - late final RiveAnimationController _riveController; - bool _isStartPressed = false; - - @override - void initState() { - _solverClient = widget.solverClient; - _puzzleSize = widget.puzzleSize; - _initialPuzzleData = widget.initialPuzzleData; - _puzzleType = widget.puzzleType; - _riveController = widget.riveController; - super.initState(); - } - - @override - Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { - if (next is PuzzleSolved) { - // TODO: Add celebration - } - if (next is PuzzleInitializing) { - setState(() { - _isStartPressed = true; - }); - } - }); - - var fontSize = 48.0; - var boardSize = 300.0; - - var spacing = 3; - var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1)); - - return Stack( - children: [ - Scaffold( - backgroundColor: Theme.of(context).backgroundColor, - body: Stack( - children: [ - Row( - children: [ - const Spacer(), - AnimatedDash( - boardSize: boardSize / 1.5, - riveController: _riveController, - onInit: (_) => setState(() {}), - padding: const EdgeInsets.only(right: 16.0, bottom: 30), - ), - ], - ), - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row(), - const SizedBox(height: 30), - const Text( - 'Puzzle Challenge', - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - const SizedBox(height: 8), - MovesTilesWidget( - solverClient: _solverClient, - fontSize: 22, - ), - const SizedBox(height: 8), - const TimerWidget(fontSize: 24), - PuzzleWidget( - solverClient: _solverClient, - boardSize: boardSize, - eachBoxSize: eachBoxSize, - initialPuzzleData: _initialPuzzleData, - fontSize: fontSize, - kInitialSpeed: kInitialSpeed, - borderRadius: 16, - ), - const SizedBox(height: 24), - GameButtonWidget( - solverClient: _solverClient, - initialPuzzleData: _initialPuzzleData, - padding: const EdgeInsets.only(top: 10.0, bottom: 9.0), - width: 130, - ), - const SizedBox(height: 100), - ], - ), - ), - ], - ), - ), - CountdownOverlay( - isStartPressed: _isStartPressed, - onFinish: () { - ref.read(timerNotifierProvider.notifier).startTimer(); - setState(() { - _isStartPressed = false; - }); - }, - initialSpeed: kInitialSpeed, - ), - ], - ); - } -} diff --git a/lib/utils/toast.dart b/lib/utils/toast.dart new file mode 100644 index 0000000..9b2fb11 --- /dev/null +++ b/lib/utils/toast.dart @@ -0,0 +1,198 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +enum Toast { + short, + long, +} + +enum ToastGravity { + top, + bottom, + center, + topLeft, + topRight, + bottomLeft, + bottomRight, + centerLEft, + centerRight, + snackBar, +} + +typedef PositionedToastBuilder = Widget Function(BuildContext context, Widget child); + +class FToast { + late BuildContext context; + + static final FToast _instance = FToast._internal(); + + factory FToast() { + return _instance; + } + + FToast init(BuildContext context) { + _instance.context = context; + return _instance; + } + + FToast._internal(); + + OverlayEntry? _entry; + final List<_ToastEntry> _overlayQueue = []; + Timer? _timer; + + void _showOverlay() { + if (_overlayQueue.isEmpty) { + _entry = null; + return; + } + _ToastEntry toastEntry = _overlayQueue.removeAt(0); + _entry = toastEntry.entry; + Overlay.of(context)?.insert(_entry!); + + _timer = Timer(toastEntry.duration, () { + Future.delayed(const Duration(milliseconds: 360), () { + removeCustomToast(); + }); + }); + } + + void removeCustomToast() { + _timer!.cancel(); + _timer = null; + if (_entry != null) _entry!.remove(); + _entry = null; + _showOverlay(); + } + + void removeQueuedCustomToasts() { + _timer?.cancel(); + _timer = null; + _overlayQueue.clear(); + if (_entry != null) _entry!.remove(); + _entry = null; + } + + void showToast({ + required Widget child, + PositionedToastBuilder? positionedToastBuilder, + required Duration? toastDuration, + required ToastGravity gravity, + int fadeDuration = 350, + }) { + Widget newChild = _ToastStateFul(child, toastDuration ?? const Duration(seconds: 2), fadeDuration: fadeDuration); + if (gravity == ToastGravity.bottom) { + if (MediaQuery.of(context).viewInsets.bottom != 0) { + gravity = ToastGravity.center; + } + } + OverlayEntry newEntry = OverlayEntry(builder: (context) { + if (positionedToastBuilder != null) return positionedToastBuilder(context, newChild); + return _getPositionWidgetBasedOnGravity(newChild, gravity); + }); + + _overlayQueue.add(_ToastEntry(entry: newEntry, duration: toastDuration ?? const Duration(seconds: 2))); + if (_timer == null) _showOverlay(); + } + + Positioned _getPositionWidgetBasedOnGravity(Widget child, ToastGravity gravity) { + switch (gravity) { + case ToastGravity.top: + return Positioned(top: 100.0, left: 24.0, right: 24.0, child: child); + case ToastGravity.topLeft: + return Positioned(top: 100.0, left: 24.0, child: child); + case ToastGravity.topRight: + return Positioned(top: 100.0, right: 24.0, child: child); + case ToastGravity.center: + return Positioned(top: 50.0, bottom: 50.0, left: 24.0, right: 24.0, child: child); + case ToastGravity.centerLEft: + return Positioned(top: 50.0, bottom: 50.0, left: 24.0, child: child); + case ToastGravity.centerRight: + return Positioned(top: 50.0, bottom: 50.0, right: 24.0, child: child); + case ToastGravity.bottomLeft: + return Positioned(bottom: 50.0, left: 24.0, child: child); + case ToastGravity.bottomRight: + return Positioned(bottom: 50.0, right: 24.0, child: child); + case ToastGravity.snackBar: + return Positioned(bottom: MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, child: child); + case ToastGravity.bottom: + default: + return Positioned(bottom: 50.0, left: 24.0, right: 24.0, child: child); + } + } +} + +class _ToastEntry { + final OverlayEntry entry; + final Duration duration; + + _ToastEntry({required this.entry, required this.duration}); +} + +class _ToastStateFul extends StatefulWidget { + const _ToastStateFul(this.child, this.duration, {Key? key, this.fadeDuration = 350}) : super(key: key); + + final Widget child; + final Duration duration; + final int fadeDuration; + + @override + ToastStateFulState createState() => ToastStateFulState(); +} + +class ToastStateFulState extends State<_ToastStateFul> with SingleTickerProviderStateMixin { + void showIt() { + _animationController.forward(); + } + + void hideIt() { + _animationController.reverse(); + _timer.cancel(); + } + + late AnimationController _animationController; + late Animation _fadeAnimation; + late Timer _timer; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: widget.fadeDuration), + ); + _fadeAnimation = CurvedAnimation(parent: _animationController, curve: Curves.easeIn); + super.initState(); + showIt(); + _timer = Timer(widget.duration, () { + hideIt(); + }); + } + + @override + void deactivate() { + _timer.cancel(); + _animationController.stop(); + super.deactivate(); + } + + @override + void dispose() { + _timer.cancel(); + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return FadeTransition( + opacity: _fadeAnimation as Animation, + child: Center( + child: Material( + color: Colors.transparent, + child: widget.child, + ), + ), + ); + } +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f3d4b4c --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,49 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:my_flutter_puzzle/utils/toast.dart'; + +class Utils { + Utils.privateConstructor(); + + static final Utils instance = Utils.privateConstructor(); + + factory Utils() { + return instance; + } + + void showToast(BuildContext? context, String? txt, {bool isError = true, ToastGravity gravity = ToastGravity.top}) { + try { + if (context == null) return; + if (txt == null || txt.isEmpty) { + if (isError == false) { + return; + } + txt = 'Error'; + } + FToast fToast = FToast(); + fToast.init(context); + Widget toast = Container( + padding: const EdgeInsetsDirectional.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: isError ? Colors.red : Colors.lightBlue, + ), + child: Text( + txt, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ); + fToast.showToast(child: toast, gravity: gravity, toastDuration: const Duration(milliseconds: 1500)); + } catch (e) { + assert(() { + if (kDebugMode) { + print(e); + } + return true; + }()); + } + } +} diff --git a/lib/widgets/puzzle_widgets/timer_test_screen.dart b/lib/widgets/puzzle_widgets/timer_test_screen.dart deleted file mode 100644 index be76c5e..0000000 --- a/lib/widgets/puzzle_widgets/timer_test_screen.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:my_flutter_puzzle/providers.dart'; - -class TimerTestScreen extends ConsumerWidget { - const TimerTestScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final state = ref.watch(timerNotifierProvider); - - return Scaffold( - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(state), - ElevatedButton( - onPressed: () => ref.read(timerNotifierProvider.notifier).startTimer(), - child: const Text('Start timer'), - ), - ElevatedButton( - onPressed: () => ref.read(timerNotifierProvider.notifier).stopTimer(), - child: const Text('Stop timer'), - ), - ], - ), - ); - } -} diff --git a/lib/widgets/solo_screen/count_down_timer_widget.dart b/lib/widgets/solo_screen/count_down_timer_widget.dart index be6b452..a73e2e7 100644 --- a/lib/widgets/solo_screen/count_down_timer_widget.dart +++ b/lib/widgets/solo_screen/count_down_timer_widget.dart @@ -33,6 +33,9 @@ class _CountDownTimerWidgetState extends State { } void stopTimer() { + if (_countdownTimer == null) { + return; + } setState(() => _countdownTimer!.cancel()); } diff --git a/lib/widgets/solo_screen/game_button_widget.dart b/lib/widgets/solo_screen/game_button_widget.dart index b311f04..acd82ba 100644 --- a/lib/widgets/solo_screen/game_button_widget.dart +++ b/lib/widgets/solo_screen/game_button_widget.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart'; import 'package:my_flutter_puzzle/models/puzzle_data.dart'; import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/utils/puzzle_solver.dart'; @@ -49,15 +51,7 @@ class GameButtonWidget extends StatelessWidget { padding: padding, width: width, ), - current: (puzzleData) => PuzzleGameButton( - text: 'Restart', - onTap: () { - ref.read(timerNotifierProvider.notifier).stopTimer(); - ref.read(puzzleNotifierProvider(_solverClient).notifier).restartPuzzle(); - }, - padding: padding, - width: width, - ), + current: (puzzleData) => const SizedBox(), computingSolution: (puzzleData) => PuzzleGameButton( text: 'Processing...', onTap: null, diff --git a/lib/widgets/solo_screen/game_button_widget/puzzle_game_button.dart b/lib/widgets/solo_screen/game_button_widget/puzzle_game_button.dart index 9c1b63e..d4a929a 100644 --- a/lib/widgets/solo_screen/game_button_widget/puzzle_game_button.dart +++ b/lib/widgets/solo_screen/game_button_widget/puzzle_game_button.dart @@ -28,24 +28,14 @@ class PuzzleGameButton extends ConsumerWidget { (Set states) { if (states.contains(MaterialState.pressed)) { return Theme.of(context).colorScheme.primary.withOpacity(0.5); - } else if (states.contains(MaterialState.disabled)) { + } + if (states.contains(MaterialState.disabled)) { return Theme.of(context).colorScheme.primary.withOpacity(0.5); } - - return Theme.of(context) - .colorScheme - .primary; // Use the component's default. + return Theme.of(context).colorScheme.primary; }, ), ), - // style: ElevatedButton.styleFrom( - // onPrimary: Palette.blue, - // onSurface: Palette.blue, - // primary: Palette.blue, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(30), - // ), - // ), onPressed: onTap, child: Padding( padding: padding,