Browse Source

fix show image bug

add timer
master
mohsen zamani 2 years ago
parent
commit
3b77ebda3d
  1. 8
      lib/application/notifiers/image_splitter_notifier.dart
  2. 6
      lib/cubits/base_cubit_type.dart
  3. 18
      lib/cubits/count_down_timer_cubit.dart
  4. 51
      lib/main.dart
  5. 71
      lib/screens/photo/photo_screen_large.dart
  6. 12
      lib/screens/puzzle/puzzle_starter_screen.dart
  7. 102
      lib/widgets/solo_screen/count_down_timer_widget.dart
  8. 1
      lib/widgets/solo_screen/countdown_widget.dart
  9. 16
      lib/widgets/solo_screen/game_button_widget.dart
  10. 32
      pubspec.lock
  11. 1
      pubspec.yaml

8
lib/application/notifiers/image_splitter_notifier.dart

@ -13,18 +13,18 @@ class ImageSplitterNotifier extends StateNotifier<ImageSplitterState> {
ImageSplitterNotifier(this._splitter) : super(const ImageSplitterState()); ImageSplitterNotifier(this._splitter) : super(const ImageSplitterState());
void getInitialImages({required int puzzleSize}) async {
void getInitialImages({required int puzzleSize, required String imagePath}) async {
state = const ImageSplitterState.generating(); state = const ImageSplitterState.generating();
try { try {
final data = await rootBundle.load(defaultImagePath);
final data = await rootBundle.load(imagePath);
final imageBytes = data.buffer.asUint8List(); final imageBytes = data.buffer.asUint8List();
final _splitter = ImageSplitter(); final _splitter = ImageSplitter();
final palette = await _splitter.getImagePalette(const AssetImage(defaultImagePath));
final palette = await _splitter.getImagePalette(AssetImage(imagePath));
final images = await _splitter.runSplitterIsolate(imageBytes, puzzleSize); final images = await _splitter.runSplitterIsolate(imageBytes, puzzleSize);
state = ImageSplitterState.complete(Image.asset(defaultImagePath), images, palette);
state = ImageSplitterState.complete(Image.asset(imagePath), images, palette);
} catch (e) { } catch (e) {
state = ImageSplitterState.error(message: e.toString()); state = ImageSplitterState.error(message: e.toString());
} }

6
lib/cubits/base_cubit_type.dart

@ -0,0 +1,6 @@
class BaseCubitType<T> {
BaseCubitType({this.eventName, this.data});
T? eventName;
dynamic data;
}

18
lib/cubits/count_down_timer_cubit.dart

@ -0,0 +1,18 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:my_flutter_puzzle/cubits/base_cubit_type.dart';
class CountDownTimerCubit extends Cubit<BaseCubitType<CountDownTimerState>> {
CountDownTimerCubit() : super(BaseCubitType(eventName: CountDownTimerState.empty));
void empty() => emit(BaseCubitType(eventName: CountDownTimerState.empty));
void start() => emit(BaseCubitType(eventName: CountDownTimerState.start));
void stop() => emit(BaseCubitType(eventName: CountDownTimerState.stop));
}
enum CountDownTimerState {
empty,
start,
stop,
}

51
lib/main.dart

@ -1,11 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart';
import 'package:my_flutter_puzzle/res/palette.dart'; import 'package:my_flutter_puzzle/res/palette.dart';
import 'package:my_flutter_puzzle/screens/level_list/screen/level_list_screen.dart'; import 'package:my_flutter_puzzle/screens/level_list/screen/level_list_screen.dart';
import 'package:my_flutter_puzzle/screens/puzzle/puzzle_starter_screen.dart';
import 'package:my_flutter_puzzle/utils/color_brightness.dart'; import 'package:my_flutter_puzzle/utils/color_brightness.dart';
import 'package:my_flutter_puzzle/utils/extensions/string_extensions.dart';
import 'package:url_strategy/url_strategy.dart'; import 'package:url_strategy/url_strategy.dart';
void main() async { void main() async {
@ -25,31 +25,30 @@ class MyApp extends StatelessWidget {
DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight, DeviceOrientation.landscapeRight,
]); ]);
return MaterialApp(
title: 'Flutter Puzzle',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
fontFamily: 'GoogleSans',
backgroundColor: Palette.blue.darken(0.3),
colorScheme: ColorScheme(
brightness: Theme.of(context).brightness,
primary: Palette.blue,
onPrimary: Colors.white,
secondary: Palette.blue.withOpacity(0.6),
onSecondary: Palette.blue.withOpacity(0.3),
error: Theme.of(context).colorScheme.error,
onError: Theme.of(context).colorScheme.onError,
background: Palette.blue.darken(0.3),
onBackground: Colors.white,
surface: Palette.crimson,
onSurface: Colors.white38,
return BlocProvider(
create: (context) => CountDownTimerCubit(),
child: MaterialApp(
title: 'Flutter Puzzle',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
fontFamily: 'GoogleSans',
backgroundColor: Palette.blue.darken(0.3),
colorScheme: ColorScheme(
brightness: Theme.of(context).brightness,
primary: Palette.blue,
onPrimary: Colors.white,
secondary: Palette.blue.withOpacity(0.6),
onSecondary: Palette.blue.withOpacity(0.3),
error: Theme.of(context).colorScheme.error,
onError: Theme.of(context).colorScheme.onError,
background: Palette.blue.darken(0.3),
onBackground: Colors.white,
surface: Palette.crimson,
onSurface: Colors.white38,
),
), ),
),
home: PuzzleStarterScreen(
duration: 3,
puzzleSize: 5,
image: 'default_image'.pngPath,
home: const LevelListScreen(),
), ),
); );
} }

71
lib/screens/photo/photo_screen_large.dart

@ -1,14 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image_picker/image_picker.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/image_splitter_state.dart';
import 'package:my_flutter_puzzle/application/states/puzzle_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/models/puzzle_data.dart';
import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/providers.dart';
import 'package:my_flutter_puzzle/res/puzzle_constants.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/puzzle_solver.dart';
import 'package:my_flutter_puzzle/widgets/photo_screen/image_viewer.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/count_down_timer_widget.dart';
import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart'; import 'package:my_flutter_puzzle/widgets/solo_screen/solo_screen_export.dart';
import 'package:palette_generator/palette_generator.dart'; import 'package:palette_generator/palette_generator.dart';
import 'package:rive/rive.dart'; import 'package:rive/rive.dart';
@ -39,7 +41,10 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
bool _isStartPressed = false; bool _isStartPressed = false;
final _imagePicker = ImagePicker(); final _imagePicker = ImagePicker();
final double _fontSize = 70.0;
final double _boardSize = 280.0;
final int _spacing = 4;
late double _eachBoxSize;
List<Image>? _previousImages; List<Image>? _previousImages;
Image? _previousImage; Image? _previousImage;
PaletteGenerator? _previousPalette; PaletteGenerator? _previousPalette;
@ -48,6 +53,7 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
void initState() { void initState() {
_solverClient = widget.solverClient; _solverClient = widget.solverClient;
_puzzleSize = widget.puzzleSize; _puzzleSize = widget.puzzleSize;
_eachBoxSize = (_boardSize / _puzzleSize) - (_spacing * (_puzzleSize - 1));
_initialPuzzleData = widget.initialPuzzleData; _initialPuzzleData = widget.initialPuzzleData;
_riveController = widget.riveController; _riveController = widget.riveController;
super.initState(); super.initState();
@ -73,12 +79,6 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
} }
}); });
var fontSize = 70.0;
var boardSize = 280.0;
var spacing = 4;
var eachBoxSize = (boardSize / _puzzleSize) - (spacing * (_puzzleSize - 1));
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.background,
body: SafeArea( body: SafeArea(
@ -105,7 +105,11 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
const TimerWidget(fontSize: 30),
// const TimerWidget(fontSize: 30),
CountDownTimerWidget(
duration: 3,
finishCallback: () {},
),
const SizedBox(height: 12), const SizedBox(height: 12),
Consumer( Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
@ -114,10 +118,10 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
return state.maybeWhen( return state.maybeWhen(
() => PuzzleWidget( () => PuzzleWidget(
solverClient: _solverClient, solverClient: _solverClient,
boardSize: boardSize,
eachBoxSize: eachBoxSize,
boardSize: _boardSize,
eachBoxSize: _eachBoxSize,
initialPuzzleData: _initialPuzzleData, initialPuzzleData: _initialPuzzleData,
fontSize: fontSize,
fontSize: _fontSize,
images: _previousImages, images: _previousImages,
kInitialSpeed: kInitialSpeed, kInitialSpeed: kInitialSpeed,
), ),
@ -128,20 +132,20 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
return PuzzleWidget( return PuzzleWidget(
solverClient: _solverClient, solverClient: _solverClient,
boardSize: boardSize,
eachBoxSize: eachBoxSize,
boardSize: _boardSize,
eachBoxSize: _eachBoxSize,
initialPuzzleData: _initialPuzzleData, initialPuzzleData: _initialPuzzleData,
fontSize: fontSize,
fontSize: _fontSize,
images: images, images: images,
kInitialSpeed: kInitialSpeed, kInitialSpeed: kInitialSpeed,
); );
}, },
orElse: () => PuzzleWidget( orElse: () => PuzzleWidget(
solverClient: _solverClient, solverClient: _solverClient,
boardSize: boardSize,
eachBoxSize: eachBoxSize,
boardSize: _boardSize,
eachBoxSize: _eachBoxSize,
initialPuzzleData: _initialPuzzleData, initialPuzzleData: _initialPuzzleData,
fontSize: fontSize,
fontSize: _fontSize,
images: _previousImages, images: _previousImages,
kInitialSpeed: kInitialSpeed, kInitialSpeed: kInitialSpeed,
), ),
@ -157,7 +161,7 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
child: Stack( child: Stack(
children: [ children: [
AnimatedDash( AnimatedDash(
boardSize: boardSize * 0.8,
boardSize: _boardSize * 0.8,
riveController: _riveController, riveController: _riveController,
onInit: (_) => setState(() {}), onInit: (_) => setState(() {}),
), ),
@ -169,7 +173,8 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
CountdownWidget( CountdownWidget(
isStartPressed: _isStartPressed, isStartPressed: _isStartPressed,
onFinish: () { onFinish: () {
ref.read(timerNotifierProvider.notifier).startTimer();
// ref.read(timerNotifierProvider.notifier).startTimer();
BlocProvider.of<CountDownTimerCubit>(context).start();
setState(() { setState(() {
_isStartPressed = false; _isStartPressed = false;
}); });
@ -178,25 +183,12 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
), ),
Visibility( Visibility(
visible: !_isStartPressed, visible: !_isStartPressed,
child: Column(
children: [
ImageViewer(
imagePicker: _imagePicker,
puzzleSize: _puzzleSize,
previousImage: _previousImage,
previousPalette: _previousPalette,
imageSize: 200,
),
PickImageButton(
text: 'Pick Image',
onTap: ref.read(imageSplitterNotifierProvider) is ImageSplitterComplete
? () => ref.read(imageSplitterNotifierProvider.notifier).generateImages(
picker: _imagePicker,
puzzleSize: _puzzleSize,
)
: null,
),
],
child: ImageViewer(
imagePicker: _imagePicker,
puzzleSize: _puzzleSize,
previousImage: _previousImage,
previousPalette: _previousPalette,
imageSize: 200,
), ),
), ),
], ],
@ -204,7 +196,6 @@ class _SoloScreenLargeState extends ConsumerState<PhotoScreenLarge> {
], ],
), ),
), ),
// SizedBox(),
], ],
), ),
), ),

12
lib/screens/puzzle/puzzle_starter_screen.dart

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/application/states/puzzle_state.dart';
import 'package:my_flutter_puzzle/models/puzzle_data.dart'; import 'package:my_flutter_puzzle/models/puzzle_data.dart';
import 'package:my_flutter_puzzle/providers.dart'; import 'package:my_flutter_puzzle/providers.dart';
@ -35,6 +36,17 @@ class _SoloScreenState extends ConsumerState<PuzzleStarterScreen> {
_riveController = SimpleAnimation('idle'); _riveController = SimpleAnimation('idle');
_solverClient = PuzzleSolverClient(size: _puzzleSize); _solverClient = PuzzleSolverClient(size: _puzzleSize);
_initialPuzzleData = ref.read(puzzleNotifierProvider(_solverClient).notifier).generateInitialPuzzle(); _initialPuzzleData = ref.read(puzzleNotifierProvider(_solverClient).notifier).generateInitialPuzzle();
final state = ref.read(imageSplitterNotifierProvider);
if (state is! ImageSplitterComplete) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
ref.read(imageSplitterNotifierProvider.notifier).getInitialImages(
puzzleSize: _puzzleSize,
imagePath: widget.image,
);
});
}
ref.read(puzzleTypeNotifierProvider.notifier).changeToPhoto();
super.initState(); super.initState();
} }

102
lib/widgets/solo_screen/count_down_timer_widget.dart

@ -0,0 +1,102 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:my_flutter_puzzle/cubits/base_cubit_type.dart';
import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart';
class CountDownTimerWidget extends StatefulWidget {
final int duration;
final Function() finishCallback;
const CountDownTimerWidget({Key? key, required this.duration, required this.finishCallback}) : super(key: key);
@override
State<CountDownTimerWidget> createState() => _CountDownTimerWidgetState();
}
class _CountDownTimerWidgetState extends State<CountDownTimerWidget> {
Timer? _countdownTimer;
Duration? myDuration;
late final CountDownTimerCubit _cubit;
@override
void initState() {
_cubit = BlocProvider.of<CountDownTimerCubit>(context);
myDuration = Duration(minutes: widget.duration);
super.initState();
}
void startTimer() {
myDuration = Duration(minutes: widget.duration);
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (_) => setCountDown());
}
void stopTimer() {
setState(() => _countdownTimer!.cancel());
}
void resetTimer() {
stopTimer();
setState(() => myDuration = const Duration(days: 5));
}
void setCountDown() {
const reduceSecondsBy = 1;
setState(() {
final seconds = myDuration!.inSeconds - reduceSecondsBy;
if (seconds < 0) {
widget.finishCallback.call();
_countdownTimer!.cancel();
} else {
myDuration = Duration(seconds: seconds);
}
});
}
@override
Widget build(BuildContext context) {
String strDigits(int n) => n.toString().padLeft(2, '0');
final hours = strDigits(myDuration!.inHours.remainder(24));
final minutes = strDigits(myDuration!.inMinutes.remainder(60));
final seconds = strDigits(myDuration!.inSeconds.remainder(60));
return BlocBuilder<CountDownTimerCubit, BaseCubitType<CountDownTimerState>>(
builder: (context, state) {
switch (state.eventName!) {
case CountDownTimerState.empty:
break;
case CountDownTimerState.start:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
startTimer();
_cubit.empty();
});
break;
case CountDownTimerState.stop:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
stopTimer();
_cubit.empty();
});
break;
}
return Row(
children: [
Text(
'$hours:$minutes:$seconds',
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(width: 8),
const Icon(
Icons.timer,
color: Colors.white,
size: 30,
)
],
);
},
);
}
}

1
lib/widgets/solo_screen/countdown_widget.dart

@ -30,7 +30,6 @@ class CountdownWidget extends ConsumerWidget {
fontFamily: 'GoogleSans', fontFamily: 'GoogleSans',
), ),
child: AnimatedTextKit( child: AnimatedTextKit(
// totalRepeatCount: 1,
isRepeatingAnimation: false, isRepeatingAnimation: false,
pause: const Duration(milliseconds: 0), pause: const Duration(milliseconds: 0),
onFinished: _onFinish, onFinished: _onFinish,

16
lib/widgets/solo_screen/game_button_widget.dart

@ -31,9 +31,7 @@ class GameButtonWidget extends StatelessWidget {
return state.when( return state.when(
() => PuzzleGameButton( () => PuzzleGameButton(
text: 'Start Game', text: 'Start Game',
onTap: () => ref
.read(puzzleNotifierProvider(_solverClient).notifier)
.initializePuzzle(
onTap: () => ref.read(puzzleNotifierProvider(_solverClient).notifier).initializePuzzle(
initialPuzzleData: _initialPuzzleData, initialPuzzleData: _initialPuzzleData,
), ),
padding: padding, padding: padding,
@ -55,9 +53,7 @@ class GameButtonWidget extends StatelessWidget {
text: 'Restart', text: 'Restart',
onTap: () { onTap: () {
ref.read(timerNotifierProvider.notifier).stopTimer(); ref.read(timerNotifierProvider.notifier).stopTimer();
ref
.read(puzzleNotifierProvider(_solverClient).notifier)
.restartPuzzle();
ref.read(puzzleNotifierProvider(_solverClient).notifier).restartPuzzle();
}, },
padding: padding, padding: padding,
width: width, width: width,
@ -76,9 +72,7 @@ class GameButtonWidget extends StatelessWidget {
), ),
solved: (puzzleData) => PuzzleGameButton( solved: (puzzleData) => PuzzleGameButton(
text: 'Start Game', text: 'Start Game',
onTap: () => ref
.read(puzzleNotifierProvider(_solverClient).notifier)
.initializePuzzle(
onTap: () => ref.read(puzzleNotifierProvider(_solverClient).notifier).initializePuzzle(
initialPuzzleData: puzzleData, initialPuzzleData: puzzleData,
), ),
padding: padding, padding: padding,
@ -86,9 +80,7 @@ class GameButtonWidget extends StatelessWidget {
), ),
error: (_) => PuzzleGameButton( error: (_) => PuzzleGameButton(
text: 'Start Game', text: 'Start Game',
onTap: () => ref
.read(puzzleNotifierProvider(_solverClient).notifier)
.initializePuzzle(
onTap: () => ref.read(puzzleNotifierProvider(_solverClient).notifier).initializePuzzle(
initialPuzzleData: _initialPuzzleData, initialPuzzleData: _initialPuzzleData,
), ),
padding: padding, padding: padding,

32
pubspec.lock

@ -49,6 +49,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.10.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: "658a5ae59edcf1e58aac98b000a71c762ad8f46f1394c34a52050cafb3e11a80"
url: "https://pub.dev"
source: hosted
version: "8.1.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -254,6 +262,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
sha256: "434951eea948dbe87f737b674281465f610b8259c16c097b8163ce138749a775"
url: "https://pub.dev"
source: hosted
version: "8.1.2"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -488,6 +504,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -608,6 +632,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:

1
pubspec.yaml

@ -21,6 +21,7 @@ dependencies:
palette_generator: ^0.3.3 palette_generator: ^0.3.3
path_provider: ^2.0.8 path_provider: ^2.0.8
image_picker: ^0.8.4+5 image_picker: ^0.8.4+5
flutter_bloc: ^8.1.1
font_awesome_flutter: ^9.2.0 font_awesome_flutter: ^9.2.0
crop: ^0.5.2 crop: ^0.5.2

Loading…
Cancel
Save