diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f6ab0f9..334f781 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ { _box = await Hive.openBox(getBoxName()); } - void updateData({required Level level}) async { + Future updateData({required Level level}) async { if (!Hive.isBoxOpen(getBoxName())) { await openBox(); } @@ -60,16 +62,23 @@ class LevelBox implements BaseBoxInterface { if (!Hive.isBoxOpen(getBoxName())) { await openBox(); } - return _box?.values.cast().toList() ?? []; + if(_box?.get(getKeyName(LevelBoxKeys.levelList)) == null) { + return []; + } + var data = jsonDecode(_box?.get(getKeyName(LevelBoxKeys.levelList))) ?? []; + List list = (data).map((item) { + return Level.fromJson(item); + }).toList(); + return list; } Future saveData(List data) async { if (!Hive.isBoxOpen(getBoxName())) { await openBox(); } - _box?.addAll(data); - for (var value in data) { - await value.save(); - } + var e = data.map((element) { + return element.toJson(); + }).toList(); + _box?.put(getKeyName(LevelBoxKeys.levelList), jsonEncode(e)); } } diff --git a/data/data_types/types/lib/level_data/interface/level_box_repository_impl.dart b/data/data_types/types/lib/level_data/interface/level_box_repository_impl.dart index e584091..d8f5593 100644 --- a/data/data_types/types/lib/level_data/interface/level_box_repository_impl.dart +++ b/data/data_types/types/lib/level_data/interface/level_box_repository_impl.dart @@ -8,7 +8,7 @@ class LevelBoxRepositoryImpl extends LevelBoxRepository { LevelBoxRepositoryImpl({required LevelBox levelBox}) : _levelBox = levelBox; @override - Future getLevel({required void Function(List data) result}) async { + Future> saveBaseLevelList() async { final List levelList = []; levelList.add(Level( image: 'assets/images/jpg/level-1.jpg', @@ -63,7 +63,7 @@ class LevelBoxRepositoryImpl extends LevelBoxRepository { payable: true, )); _levelBox.saveData(levelList); - result.call(levelList); + return levelList; } @override @@ -80,4 +80,14 @@ class LevelBoxRepositoryImpl extends LevelBoxRepository { Future setCurrentLevel(int level) async { await _levelBox.setCurrentLevel(level); } + + @override + Future updateLevel(Level level) async { + await _levelBox.updateData(level: level); + } + + @override + Future> getFilledLevelList() async { + return await _levelBox.getData(); + } } diff --git a/domain/repositories/android/local.properties b/domain/repositories/android/local.properties new file mode 100644 index 0000000..be2bbdc --- /dev/null +++ b/domain/repositories/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Work\\Tools\\Sdk +flutter.sdk=C:\\Work\\Tools\\flutter \ No newline at end of file diff --git a/domain/repositories/ios/Flutter/Generated.xcconfig b/domain/repositories/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..2654c1b --- /dev/null +++ b/domain/repositories/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=C:\Work\Tools\flutter +FLUTTER_APPLICATION_PATH=C:\Users\user1\StudioProjects\habib_kids\domain\repositories +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/domain/repositories/ios/Flutter/flutter_export_environment.sh b/domain/repositories/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 0000000..c636ef1 --- /dev/null +++ b/domain/repositories/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\Work\Tools\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\user1\StudioProjects\habib_kids\domain\repositories" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/domain/repositories/lib/level_box_domain/adapter/level_model_adapter.dart b/domain/repositories/lib/level_box_domain/adapter/level_model_adapter.dart index 8cff757..493fa7f 100644 --- a/domain/repositories/lib/level_box_domain/adapter/level_model_adapter.dart +++ b/domain/repositories/lib/level_box_domain/adapter/level_model_adapter.dart @@ -16,7 +16,7 @@ class LevelModelAdapter extends TypeAdapter { puzzleSize: fields[1] as int, duration: fields[2] as int, level: fields[3] as int, - recordDuration: fields[4] as int, + recordDuration: fields[4] as String, payable: fields[5] as bool, ); } diff --git a/domain/repositories/lib/level_box_domain/model/level_model.dart b/domain/repositories/lib/level_box_domain/model/level_model.dart index d6de13c..c664279 100644 --- a/domain/repositories/lib/level_box_domain/model/level_model.dart +++ b/domain/repositories/lib/level_box_domain/model/level_model.dart @@ -11,7 +11,7 @@ class Level extends HiveObject { @HiveField(3) final int level; @HiveField(4) - final int recordDuration; + String recordDuration; @HiveField(5) final bool payable; @@ -20,7 +20,7 @@ class Level extends HiveObject { required this.duration, required this.puzzleSize, required this.level, - this.recordDuration = 0, + this.recordDuration = '', this.payable = false, }); @@ -34,4 +34,15 @@ class Level extends HiveObject { 'payable': payable, }; } + + factory Level.fromJson(Map json) { + return Level( + image: json['image'], + duration: json['duration'], + puzzleSize: json['puzzleSize'], + level: json['level'], + recordDuration: json['recordDuration'], + payable: json['payable'], + ); + } } diff --git a/domain/repositories/lib/level_box_domain/repository/level_box_repository.dart b/domain/repositories/lib/level_box_domain/repository/level_box_repository.dart index cc67b8c..55bb8de 100644 --- a/domain/repositories/lib/level_box_domain/repository/level_box_repository.dart +++ b/domain/repositories/lib/level_box_domain/repository/level_box_repository.dart @@ -1,11 +1,15 @@ import 'package:repositories/level_box_domain/model/level_model.dart'; abstract class LevelBoxRepository { - Future getLevel({required void Function(List data) result}); + Future> saveBaseLevelList(); Future openBox(); Future getCurrentLevel(); Future setCurrentLevel(int level); + + Future updateLevel(Level level); + + Future> getFilledLevelList(); } diff --git a/lib/cubits/count_down_timer_cubit.dart b/lib/cubits/count_down_timer_cubit.dart index bf6ad5c..b7006b8 100644 --- a/lib/cubits/count_down_timer_cubit.dart +++ b/lib/cubits/count_down_timer_cubit.dart @@ -2,12 +2,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:my_flutter_puzzle/cubits/base_cubit_type.dart'; class CountDownTimerCubit extends Cubit> { - CountDownTimerCubit() - : super( - BaseCubitType( - eventName: CountDownTimerState.empty, - ), - ); + Duration? _duration; + + CountDownTimerCubit() : super(BaseCubitType(eventName: CountDownTimerState.empty)); void empty() => emit(BaseCubitType(eventName: CountDownTimerState.empty)); @@ -16,6 +13,14 @@ class CountDownTimerCubit extends Cubit> { void stop() => emit(BaseCubitType(eventName: CountDownTimerState.stop)); void reset() => emit(BaseCubitType(eventName: CountDownTimerState.reset)); + + void setDuration(Duration duration) { + _duration = duration; + } + + Duration? getDuration() { + return _duration; + } } enum CountDownTimerState { diff --git a/lib/initializer.dart b/lib/initializer.dart index a05ee7e..9ec5bef 100644 --- a/lib/initializer.dart +++ b/lib/initializer.dart @@ -20,6 +20,5 @@ class Initializer { Hive.init(dir.path); Hive.registerAdapter(LevelModelAdapter()); await _repository.openBox(); - await _repository.setCurrentLevel(1); } } diff --git a/lib/main.dart b/lib/main.dart index 5b0e227..aa08b7e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_flutter_puzzle/cubits/count_down_timer_cubit.dart'; import 'package:my_flutter_puzzle/initializer.dart'; import 'package:my_flutter_puzzle/res/palette.dart'; +import 'package:my_flutter_puzzle/screens/level_list/cubit/level_list_cubit.dart'; +import 'package:my_flutter_puzzle/screens/level_list/screen/level_list_screen.dart'; import 'package:my_flutter_puzzle/screens/splash/screen/splash_screen.dart'; import 'package:my_flutter_puzzle/utils/color_brightness.dart'; @@ -24,30 +26,18 @@ class MyApp extends StatelessWidget { DeviceOrientation.landscapeRight, ]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); - return BlocProvider( - create: (context) => CountDownTimerCubit(), + return MultiBlocProvider( + providers: [ + BlocProvider(create: (context) => LevelListCubit()), + 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: const SplashScreen(), + initialRoute: '/', + routes: { + '/': (context) => const SplashScreen(), + 'level_list': (context) => const LevelListScreen(), + }, ), ); } diff --git a/lib/screens/level_list/cubit/level_list_cubit.dart b/lib/screens/level_list/cubit/level_list_cubit.dart index a7e87e5..f69c943 100644 --- a/lib/screens/level_list/cubit/level_list_cubit.dart +++ b/lib/screens/level_list/cubit/level_list_cubit.dart @@ -5,27 +5,55 @@ import 'package:repositories/level_box_domain/model/level_model.dart'; import 'package:repositories/level_box_domain/repository/level_box_repository.dart'; import 'package:types/level_data/interface/level_box_repository_impl.dart'; -class LevelListCubit extends Cubit> { +class LevelListCubit extends Cubit> { List levelList = []; late int currentLevel; final LevelBoxRepository _repository = LevelBoxRepositoryImpl(levelBox: LevelBox()); - LevelListCubit() : super(BaseCubitType(eventName: LevelListCubitState.empty)); + LevelListCubit() : super(BaseCubitType(eventName: LevelListState.empty)); - void empty() => emit(BaseCubitType(eventName: LevelListCubitState.empty)); + void empty() => emit(BaseCubitType(eventName: LevelListState.empty)); void getData() async { currentLevel = await _repository.getCurrentLevel(); - await _repository.getLevel( - result: (data) { - levelList = data; - emit(BaseCubitType(eventName: LevelListCubitState.list)); - }, - ); + levelList = await _repository.getFilledLevelList(); + if (levelList.isEmpty) { + levelList = await _repository.saveBaseLevelList(); + } + emit(BaseCubitType(eventName: LevelListState.list)); } + + Level getLevel() { + return levelList.firstWhere((element) => element.level == currentLevel); + } + + void setRecordDuration(int level, Duration duration, Function callback) async { + int index = levelList.indexWhere((element) => element.level == level); + if (index == -1) { + return; + } + Level playedLevel = levelList[index]; + if (playedLevel.recordDuration == '') { + playedLevel.recordDuration = _showDuration(duration, Duration(minutes: playedLevel.duration)); + currentLevel += 1; + _repository.setCurrentLevel(currentLevel); + } else { + playedLevel.recordDuration = _showDuration(duration, Duration(minutes: playedLevel.duration)); + } + await _repository.updateLevel(playedLevel); + callback.call(); + } + + String _showDuration(Duration duration, Duration baseDuration) { + final minutes = strDigits((baseDuration - duration).inMinutes.remainder(60)); + final seconds = strDigits((baseDuration - duration).inSeconds.remainder(60)); + return '$minutes:$seconds'; + } + + String strDigits(int n) => n.toString().padLeft(2, '0'); } -enum LevelListCubitState { +enum LevelListState { empty, list, } diff --git a/lib/screens/level_list/screen/level_list_screen.dart b/lib/screens/level_list/screen/level_list_screen.dart index 73f9fc3..cdff0fa 100644 --- a/lib/screens/level_list/screen/level_list_screen.dart +++ b/lib/screens/level_list/screen/level_list_screen.dart @@ -5,9 +5,7 @@ import 'package:my_flutter_puzzle/screens/level_list/cubit/level_list_cubit.dart import 'package:my_flutter_puzzle/screens/level_list/widgets/level_widget.dart'; import 'package:my_flutter_puzzle/screens/level_list/widgets/lock_level_widget.dart'; import 'package:my_flutter_puzzle/screens/level_list/widgets/payed_level_widget.dart'; -import 'package:my_flutter_puzzle/screens/lose/lose_screen.dart'; import 'package:my_flutter_puzzle/screens/puzzle/puzzle_starter_screen.dart'; -import 'package:my_flutter_puzzle/screens/win/win_screen.dart'; import 'package:my_flutter_puzzle/utils/extensions/context_extension.dart'; import 'package:my_flutter_puzzle/utils/extensions/string_extensions.dart'; import 'package:repositories/level_box_domain/model/level_model.dart'; @@ -20,12 +18,9 @@ class LevelListScreen extends StatefulWidget { } class _LevelListScreenState extends State { - late final LevelListCubit _cubit; - @override void initState() { - _cubit = BlocProvider.of(context); - _cubit.getData(); + BlocProvider.of(context).getData(); super.initState(); } @@ -33,12 +28,12 @@ class _LevelListScreenState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xff6236FF), - body: BlocBuilder>( + body: BlocBuilder>( builder: (context, state) { switch (state.eventName!) { - case LevelListCubitState.empty: + case LevelListState.empty: break; - case LevelListCubitState.list: + case LevelListState.list: break; } return Padding( @@ -73,18 +68,19 @@ class _LevelListScreenState extends State { height: context.height * 397 / 540, child: ListView.builder( itemBuilder: (context, index) { - if (_cubit.levelList[index].level == _cubit.currentLevel) { + if (BlocProvider.of(context).levelList[index].level <= + BlocProvider.of(context).currentLevel) { return GestureDetector( - onTap: () => _startLevel(_cubit.levelList[index]), - child: LevelWidget(level: _cubit.levelList[index]), + onTap: () => _startLevel(BlocProvider.of(context).levelList[index]), + child: LevelWidget(level: BlocProvider.of(context).levelList[index]), ); } - if (_cubit.levelList[index].payable) { - return PayedLevelWidget(level: _cubit.levelList[index]); + if (BlocProvider.of(context).levelList[index].payable) { + return PayedLevelWidget(level: BlocProvider.of(context).levelList[index]); } - return LockLevelWidget(level: _cubit.levelList[index]); + return LockLevelWidget(level: BlocProvider.of(context).levelList[index]); }, - itemCount: _cubit.levelList.length, + itemCount: BlocProvider.of(context).levelList.length, ), ), ], @@ -110,6 +106,8 @@ class _LevelListScreenState extends State { ); }, ), - ); + ).then((value) { + BlocProvider.of(context).getData(); + }); } } diff --git a/lib/screens/lose/lose_screen.dart b/lib/screens/lose/lose_screen.dart index 088367a..f7dd555 100644 --- a/lib/screens/lose/lose_screen.dart +++ b/lib/screens/lose/lose_screen.dart @@ -141,63 +141,68 @@ class _LoseScreenState extends State { ), Transform.translate( offset: const Offset(0, 20), - child: Container( - width: context.width * 147 / 812, - height: context.height * 51 / 375, - padding: const EdgeInsets.all(3), - decoration: BoxDecoration( - color: const Color(0xff979797).withOpacity(0.12), - borderRadius: BorderRadius.circular(36), - ), + child: GestureDetector( + onTap: () { + Navigator.pop(context, true); + }, child: Container( + width: context.width * 147 / 812, + height: context.height * 51 / 375, + padding: const EdgeInsets.all(3), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(31), - gradient: const LinearGradient( - colors: [ - Color(0xffFFC600), - Color(0xffFF5A00), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), + color: const Color(0xff979797).withOpacity(0.12), + borderRadius: BorderRadius.circular(36), ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 6), - Container( - width: context.width * 26 / 540, - height: context.width * 26 / 540, - padding: const EdgeInsets.all(9), - margin: const EdgeInsets.symmetric(vertical: 3), - decoration: BoxDecoration( - border: Border.all( - color: Colors.white, - width: 1, - ), - gradient: const LinearGradient( - colors: [ - Colors.white, - Color(0xffD5D5D5), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(31), + gradient: const LinearGradient( + colors: [ + Color(0xffFFC600), + Color(0xffFF5A00), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 6), + Container( + width: context.width * 26 / 540, + height: context.width * 26 / 540, + padding: const EdgeInsets.all(9), + margin: const EdgeInsets.symmetric(vertical: 3), + decoration: BoxDecoration( + border: Border.all( + color: Colors.white, + width: 1, + ), + gradient: const LinearGradient( + colors: [ + Colors.white, + Color(0xffD5D5D5), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + shape: BoxShape.circle, ), - shape: BoxShape.circle, + child: SvgPicture.asset('refresh'.svgPath), ), - child: SvgPicture.asset('refresh'.svgPath), - ), - const SizedBox(width: 8), - const Text( - 'Restart', - style: TextStyle( - color: Colors.white, - fontSize: 14, - fontWeight: FontWeight.bold, + const SizedBox(width: 8), + const Text( + 'Restart', + style: TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.bold, + ), ), - ), - const SizedBox(width: 14), - ], + const SizedBox(width: 14), + ], + ), ), ), ), diff --git a/lib/screens/photo/photo_screen.dart b/lib/screens/photo/photo_screen.dart index d0226a3..86f31d6 100644 --- a/lib/screens/photo/photo_screen.dart +++ b/lib/screens/photo/photo_screen.dart @@ -52,8 +52,7 @@ class _PhotoScreenState extends ConsumerState { @override Widget build(BuildContext context) { - ref.listen(puzzleNotifierProvider(_solverClient), - (previous, PuzzleState next) { + ref.listen(puzzleNotifierProvider(_solverClient), (previous, PuzzleState next) { if (next is PuzzleSolved) { BlocProvider.of(context).stop(); } @@ -70,8 +69,7 @@ class _PhotoScreenState extends ConsumerState { onSecondary: Theme.of(context).colorScheme.onSecondary, error: Theme.of(context).colorScheme.error, onError: Theme.of(context).colorScheme.onError, - background: - next.palette.darkMutedColor?.color ?? Palette.blue.darken(0.3), + background: next.palette.darkMutedColor?.color ?? Palette.blue.darken(0.3), onBackground: Colors.white, surface: Theme.of(context).colorScheme.surface, onSurface: Theme.of(context).colorScheme.onSurface, @@ -110,8 +108,7 @@ class _PhotoScreenState extends ConsumerState { onSecondary: Theme.of(context).colorScheme.onSecondary, error: Theme.of(context).colorScheme.error, onError: Theme.of(context).colorScheme.onError, - background: - palette.darkMutedColor?.color ?? Palette.blue.darken(0.3), + background: palette.darkMutedColor?.color ?? Palette.blue.darken(0.3), onBackground: Colors.white, surface: Theme.of(context).colorScheme.surface, onSurface: Theme.of(context).colorScheme.onSurface, diff --git a/lib/screens/photo/photo_screen_large.dart b/lib/screens/photo/photo_screen_large.dart index 2f83eaf..5f94a78 100644 --- a/lib/screens/photo/photo_screen_large.dart +++ b/lib/screens/photo/photo_screen_large.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -8,12 +10,12 @@ 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/puzzle_constants.dart'; +import 'package:my_flutter_puzzle/screens/level_list/cubit/level_list_cubit.dart'; import 'package:my_flutter_puzzle/screens/lose/lose_screen.dart'; import 'package:my_flutter_puzzle/screens/win/win_screen.dart'; import 'package:my_flutter_puzzle/utils/extensions/context_extension.dart'; import 'package:my_flutter_puzzle/utils/extensions/string_extensions.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/countdown_widget.dart'; @@ -68,6 +70,30 @@ class _SoloScreenLargeState extends ConsumerState { _eachBoxSize = (_boardSize / _puzzleSize) - (_spacing * (_puzzleSize - 1)); _initialPuzzleData = widget.initialPuzzleData; _riveController = widget.riveController; + Timer timer = Timer( + const Duration(seconds: 10), + () { + _puzzleSolved = true; + BlocProvider.of(context).stop(); + BlocProvider.of(context).setRecordDuration( + widget.level, + BlocProvider.of(context).getDuration() ?? Duration(minutes: widget.duration), + () { + Future.delayed(const Duration(milliseconds: 500), () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (context) { + return WinScreen( + tiles: _tiles, + move: _moves, + level: widget.level, + ); + }, + )); + }); + }, + ); + }, + ); super.initState(); } @@ -81,17 +107,24 @@ class _SoloScreenLargeState extends ConsumerState { } if (next is PuzzleSolved) { _puzzleSolved = true; - Future.delayed(const Duration(milliseconds: 500), () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return WinScreen( - tiles: _tiles, - move: _moves, - level: widget.level, - ); - }, - )); - }); + BlocProvider.of(context).stop(); + BlocProvider.of(context).setRecordDuration( + widget.level, + BlocProvider.of(context).getDuration() ?? Duration(minutes: widget.duration), + () { + Future.delayed(const Duration(milliseconds: 500), () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (context) { + return WinScreen( + tiles: _tiles, + move: _moves, + level: widget.level, + ); + }, + )); + }); + }, + ); } }); @@ -280,7 +313,14 @@ class _SoloScreenLargeState extends ConsumerState { builder: (context) { return LoseScreen(tiles: _tiles, move: _moves); }, - )); + )).then((value) { + if (value == true) { + BlocProvider.of(context).reset(); + BlocProvider.of(context).start(); + } else { + Navigator.pop(context); + } + }); }); } } diff --git a/lib/screens/splash/screen/splash_screen.dart b/lib/screens/splash/screen/splash_screen.dart index 4dae903..ae9f247 100644 --- a/lib/screens/splash/screen/splash_screen.dart +++ b/lib/screens/splash/screen/splash_screen.dart @@ -19,10 +19,7 @@ class _SplashScreenState extends State { Timer(const Duration(milliseconds: 2000), () { Navigator.push(context, MaterialPageRoute( builder: (context) { - return BlocProvider( - child: const LevelListScreen(), - create: (context) => LevelListCubit(), - ); + return const LevelListScreen(); }, )); }); diff --git a/lib/screens/win/win_screen.dart b/lib/screens/win/win_screen.dart index ced1641..01af7bc 100644 --- a/lib/screens/win/win_screen.dart +++ b/lib/screens/win/win_screen.dart @@ -1,7 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:my_flutter_puzzle/screens/level_list/cubit/level_list_cubit.dart'; +import 'package:my_flutter_puzzle/screens/puzzle/puzzle_starter_screen.dart'; import 'package:my_flutter_puzzle/utils/extensions/context_extension.dart'; import 'package:my_flutter_puzzle/utils/extensions/string_extensions.dart'; +import 'package:repositories/level_box_domain/model/level_model.dart'; class WinScreen extends StatefulWidget { final int move; @@ -151,9 +155,7 @@ class _WinScreenState extends State { Transform.translate( offset: const Offset(0, 20), child: GestureDetector( - onTap: () { - - }, + onTap: _openNextLevel, child: Container( width: context.width * 160 / 812, height: context.height * 51 / 375, @@ -232,4 +234,27 @@ class _WinScreenState extends State { ), ); } + + void _openNextLevel() { + int currentLevel = BlocProvider.of(context).currentLevel; + if (currentLevel == 8) { + // all levels are done + Navigator.popUntil(context, ModalRoute.withName('/')); + } else { + Level level = BlocProvider.of(context).getLevel(); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return PuzzleStarterScreen( + duration: level.duration, + puzzleSize: level.puzzleSize, + image: level.image, + level: level.level, + ); + }, + ), + ); + } + } } diff --git a/lib/widgets/solo_screen/count_down_timer_widget.dart b/lib/widgets/solo_screen/count_down_timer_widget.dart index f443fd8..71e500d 100644 --- a/lib/widgets/solo_screen/count_down_timer_widget.dart +++ b/lib/widgets/solo_screen/count_down_timer_widget.dart @@ -19,53 +19,21 @@ class CountDownTimerWidget extends StatefulWidget { class _CountDownTimerWidgetState extends State { Timer? _countdownTimer; - Duration? myDuration; + Duration? _duration; late final CountDownTimerCubit _cubit; @override void initState() { _cubit = BlocProvider.of(context); - myDuration = Duration(minutes: widget.duration); + _duration = Duration(minutes: widget.duration); super.initState(); } - void startTimer() { - myDuration = Duration(minutes: widget.duration); - _countdownTimer = Timer.periodic(const Duration(seconds: 1), (_) => setCountDown()); - } - - void stopTimer() { - if (_countdownTimer == null) { - return; - } - setState(() => _countdownTimer!.cancel()); - } - - void resetTimer() { - stopTimer(); - setState(() => myDuration = Duration(minutes: widget.duration)); - startTimer(); - } - - 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)); + final minutes = strDigits(_duration!.inMinutes.remainder(60)); + final seconds = strDigits(_duration!.inSeconds.remainder(60)); return BlocBuilder>( builder: (context, state) { switch (state.eventName!) { @@ -73,19 +41,19 @@ class _CountDownTimerWidgetState extends State { break; case CountDownTimerState.start: WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - startTimer(); + _startTimer(); _cubit.empty(); }); break; case CountDownTimerState.stop: WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - stopTimer(); + _stopTimer(); _cubit.empty(); }); break; case CountDownTimerState.reset: WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - resetTimer(); + _resetTimer(); _cubit.empty(); }); break; @@ -93,7 +61,7 @@ class _CountDownTimerWidgetState extends State { return Row( children: [ Text( - '$hours:$minutes:$seconds', + '$minutes:$seconds', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, @@ -107,4 +75,36 @@ class _CountDownTimerWidgetState extends State { }, ); } + + void _startTimer() { + _duration = Duration(minutes: widget.duration); + _countdownTimer = Timer.periodic(const Duration(seconds: 1), (_) => _setCountDown()); + } + + void _stopTimer() { + if (_countdownTimer == null) { + return; + } + setState(() => _countdownTimer!.cancel()); + } + + void _resetTimer() { + _stopTimer(); + setState(() => _duration = Duration(minutes: widget.duration)); + _startTimer(); + } + + void _setCountDown() { + const reduceSecondsBy = 1; + setState(() { + final seconds = _duration!.inSeconds - reduceSecondsBy; + if (seconds < 0) { + widget.finishCallback.call(); + _countdownTimer!.cancel(); + } else { + _duration = Duration(seconds: seconds); + _cubit.setDuration(_duration!); + } + }); + } } diff --git a/lib/widgets/solo_screen/moves_tiles_widget/moves_tiles_text.dart b/lib/widgets/solo_screen/moves_tiles_widget/moves_tiles_text.dart index 706bb8f..9221427 100644 --- a/lib/widgets/solo_screen/moves_tiles_widget/moves_tiles_text.dart +++ b/lib/widgets/solo_screen/moves_tiles_widget/moves_tiles_text.dart @@ -88,7 +88,7 @@ class MovesTilesText extends StatelessWidget { style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, - fontSize: 12, + fontSize: 10, ), ), ],