import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/params/level_params.dart'; import 'package:hadi_hoda_flutter/core/params/no_params.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/services/audio_service.dart'; import 'package:hadi_hoda_flutter/core/status/base_status.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/core/utils/my_context.dart'; import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; import 'package:hadi_hoda_flutter/core/widgets/dialog/reward_dialog.dart'; import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart'; import 'package:hadi_hoda_flutter/features/download/domain/usecases/get_last_downloaded_level.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_state.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_location.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/usecases/get_levels_usecase.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_state.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; class LevelBloc extends Bloc { /// ------------constructor------------ LevelBloc( this._getLeveslUseCase, this._mainAudioService, this._effectAudioService, this._getLastDownloadedLevel, ) : super(const LevelState()) { volumeStream = _mainAudioService.volumeStream(); playMusic(); on(_getLevelListEvent); on(_setCurrentLevelEvent); on(_startScrollEvent); on(_chooseLevelEvent); } @override Future close() { scrollController.dispose(); return super.close(); } /// ------------UseCases------------ final GetLevelsUseCase _getLeveslUseCase; final GetLastDownloadedLevel _getLastDownloadedLevel; /// ------------Variables------------ final List locationListShort = [ LevelLocation( bottom: setSize(context: MyContext.get, mobile: -0.01.h, tablet: -0.01.h), left: setSize(context: MyContext.get, mobile: 0.15.w, tablet: 0.25.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.03.h, tablet: 0.075.h), left: setSize(context: MyContext.get, mobile: 0.28.w, tablet: 0.38.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.09.h, tablet: 0.14.h), left: setSize(context: MyContext.get, mobile: 0.14.w, tablet: 0.18.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.17.h, tablet: 0.24.h), left: setSize(context: MyContext.get, mobile: 0.18.w, tablet: 0.225.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.22.h, tablet: 0.33.h), left: setSize(context: MyContext.get, mobile: 0.36.w, tablet: 0.3.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.245.h, tablet: 0.4.h), left: setSize(context: MyContext.get, mobile: 0.54.w, tablet: 0.55.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.305.h, tablet: 0.45.h), left: setSize(context: MyContext.get, mobile: 0.64.w, tablet: 0.75.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.38.h, tablet: 0.68.h), left: setSize(context: MyContext.get, mobile: 0.61.w, tablet: 0.735.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.455.h, tablet: 0.8.h), left: setSize(context: MyContext.get, mobile: 0.575.w, tablet: 0.68.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.53.h, tablet: .951.h), left: setSize(context: MyContext.get, mobile: 0.575.w, tablet: 0.64.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.6.h , tablet: 1.01.h), left: setSize(context: MyContext.get, mobile: 0.5.w, tablet: 0.27.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.6185.h, tablet: 1.05.h), left: setSize(context: MyContext.get, mobile: 0.33.w, tablet: 0.08.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.646.h, tablet: 1.17.h), left: setSize(context: MyContext.get, mobile: 0.143.w, tablet: 0.09.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.69.h, tablet: 1.22.h), left: setSize(context: MyContext.get, mobile: 0, tablet: 0.34.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.74.h, tablet: 1.25.h), left: setSize(context: MyContext.get, mobile: 0.07.w, tablet: 0.53.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.759.h, tablet: 1.37.h), left: setSize(context: MyContext.get, mobile: 0.21.w, tablet: 0.635.w), ), ////// LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.776.h, tablet: 1.43.h), left: setSize(context: MyContext.get, mobile: 0.345.w, tablet: 0.545.w), ), ///// LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.808.h, tablet: 1.52.h), left: setSize(context: MyContext.get, mobile: 0.475.w, tablet: 0.55.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.885.h, tablet: 1.62.h), left: setSize(context: MyContext.get, mobile: 0.465.w, tablet: 0.46.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.95.h, tablet: 1.636.h), left: setSize(context: MyContext.get, mobile: 0.47.w, tablet: 0.3.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.02.h, tablet: 1.62.h), left: setSize(context: MyContext.get, mobile: 0.45.w, tablet: 0.11.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.042.h, tablet: 1.7.h), left: setSize(context: MyContext.get, mobile: 0.2.w, tablet: 0.0.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.1.h, tablet: 1.858.h), left: setSize(context: MyContext.get, mobile: 0, tablet: 0.0.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.19.h, tablet: 1.89.h), left: setSize(context: MyContext.get, mobile: 0, tablet: 0.19.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.23.h, tablet: 1.98.h), left: setSize(context: MyContext.get, mobile: 0.23.w, tablet: 0.3.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.31.h, tablet: 2.08.h), left: setSize(context: MyContext.get, mobile: 0.2.w, tablet: 0.215.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.36.h, tablet: 2.15.h), left: setSize(context: MyContext.get, mobile: 0.09.w, tablet: 0.11.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.425.h, tablet: 2.23.h), left: setSize(context: MyContext.get, mobile: 0.09.w, tablet: 0.1.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.48.h, tablet: 2.29.h), left: setSize(context: MyContext.get, mobile: 0.184.w, tablet: 0.17.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.535.h, tablet: 2.36.h), left: setSize(context: MyContext.get, mobile: 0.22.w, tablet: 0.225.w), ), ]; final List locationListLong = [ LevelLocation( bottom: setSize(context: MyContext.get, mobile: -0.03.h, tablet: -0.03.h), left: setSize(context: MyContext.get, mobile: 0.1.w, tablet: 0.2.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.013.h, tablet: 0.075.h), left: setSize(context: MyContext.get, mobile: 0.23.w, tablet: 0.38.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.08.h, tablet: 0.14.h), left: setSize(context: MyContext.get, mobile: 0.19.w, tablet: 0.18.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.145.h, tablet: 0.24.h), left: setSize(context: MyContext.get, mobile: 0.15.w, tablet: 0.225.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.2.h, tablet: 0.33.h), left: setSize(context: MyContext.get, mobile: 0.255.w, tablet: 0.3.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.237.h, tablet: 0.4.h), left: setSize(context: MyContext.get, mobile: 0.4.w, tablet: 0.55.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.258.h, tablet: 0.45.h), left: setSize(context: MyContext.get, mobile: 0.56.w, tablet: 0.75.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.31.h, tablet: 0.55.h), left: setSize(context: MyContext.get, mobile: 0.66.w, tablet: 0.799.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.38.h, tablet: 0.65.h), left: setSize(context: MyContext.get, mobile: 0.659.w, tablet: 0.733.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.45.h, tablet: 0.78.h), left: setSize(context: MyContext.get, mobile: 0.59.w, tablet: 0.69.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.52.h, tablet: 0.89.h), left: setSize(context: MyContext.get, mobile: 0.59.w, tablet: 0.7.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.592.h, tablet: .987.h), left: setSize(context: MyContext.get, mobile: 0.56.w, tablet: 0.5.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.61.h, tablet: 1.03.h), left: setSize(context: MyContext.get, mobile: 0.4.w, tablet: 0.18.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.63.h, tablet: 1.19.h), left: setSize(context: MyContext.get, mobile: 0.24.w, tablet: 0.22.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.655.h, tablet: 1.19.h), left: setSize(context: MyContext.get, mobile: 0.10.w, tablet: 0.22.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.71.h, tablet: 1.25.h), left: setSize(context: MyContext.get, mobile: 0.009.w, tablet: 0.53.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.75.h, tablet: 1.33.h), left: setSize(context: MyContext.get, mobile: 0.15.w, tablet: 0.62.w), ), ////// LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.77.h, tablet: 1.43.h), left: setSize(context: MyContext.get, mobile: 0.31.w, tablet: 0.545.w), ), ///// LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.792.h, tablet: 1.52.h), left: setSize(context: MyContext.get, mobile: 0.46.w, tablet: 0.55.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.905.h, tablet: 1.62.h), left: setSize(context: MyContext.get, mobile: 0.465.w, tablet: 0.46.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.85.h, tablet: 1.62.h), left: setSize(context: MyContext.get, mobile: 0.525.w, tablet: 0.46.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 0.975.h, tablet: 1.636.h), left: setSize(context: MyContext.get, mobile: 0.48.w, tablet: 0.3.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.02.h, tablet: 1.62.h), left: setSize(context: MyContext.get, mobile: 0.4.w, tablet: 0.11.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.02.h, tablet: 1.7.h), left: setSize(context: MyContext.get, mobile: 0.25.w, tablet: 0.0.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.02.h, tablet: 1.7.h), left: setSize(context: MyContext.get, mobile: 0.105.w, tablet: 0.0.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.03.h, tablet: 1.825.h), left: setSize(context: MyContext.get, mobile: -0.05.w, tablet: 0.0.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.087.h, tablet: 1.88.h), left: setSize(context: MyContext.get, mobile: 0.01.w, tablet: 0.125.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.15.h, tablet: 1.88.h), left: setSize(context: MyContext.get, mobile: -0.03.w, tablet: 0.125.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.19.h, tablet: 1.97.h), left: setSize(context: MyContext.get, mobile: 0.1.w, tablet: 0.289.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.23.h, tablet: 2.10.h), left: setSize(context: MyContext.get, mobile: 0.23.w, tablet: 0.21.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.3.h, tablet: 2.169.h), left: setSize(context: MyContext.get, mobile: 0.2.w, tablet: 0.1.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.355.h, tablet: 2.25.h), left: setSize(context: MyContext.get, mobile: 0.1.w, tablet: 0.1.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.424.h, tablet: 2.34.h), left: setSize(context: MyContext.get, mobile: 0.077.w, tablet: 0.225.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.47.h, tablet: 2.34.h), left: setSize(context: MyContext.get, mobile: 0.18.w, tablet: 0.225.w), ), LevelLocation( bottom: setSize(context: MyContext.get, mobile: 1.533.h, tablet: 2.34.h), left: setSize(context: MyContext.get, mobile: 0.225.w, tablet: 0.225.w), ), // LevelLocation( // bottom: setSize(context: MyContext.get, mobile: 1.5.h, tablet: 2.8.h), // left: setSize(context: MyContext.get, mobile: 0.2.w, tablet: 0.15.w), // // ), ]; final List nodeList = []; late final Stream volumeStream; /// ------------Controllers------------ final ScrollController scrollController = ScrollController(); final AudioService _mainAudioService; final AudioService _effectAudioService; /// ------------Functions------------ Future playMusic() async { await Future.wait([ _mainAudioService.setAudio(assetPath: MyAudios.question), _mainAudioService.setLoopMode(isLoop: true), ]); await _mainAudioService.play(); } void goToQuestionPage(BuildContext context, LevelEntity level) async { final int levelOrder = level.order ?? 0; final int lastDownloadedLevel = (await _getLastDownloadedLevel(NoParams())).data ?? 0; if (!context.mounted) return; final bool isLevelDownloaded = levelOrder <= lastDownloadedLevel; if (isLevelDownloaded) { context.pushReplacementNamed( Routes.questionPage, pathParameters: {'id': '${level.id}'}, ); } else { final maxLevelCount = int.tryParse( LocalStorage.readData(key: MyConstants.maxLevelCount) ?? '20', ) ?? 20; context.pushNamed( Routes.downloadPage, extra: DownloadPageConfig( downloadToLevel: maxLevelCount, routeParams: {'id': '${level.id}'}, redirectTo: Routes.questionPage, ), ); } } void goToHomePage(BuildContext context) { context.goNamed(Routes.homePage); } LevelType getLevelType(int index) { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); if (index < currentLevel) { return LevelType.finished; } else if (index == currentLevel) { return LevelType.current; } else { return LevelType.unFinished; } } bool getReward(int index) { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); return currentLevel > index; } Future changeMute() async { await Future.wait([ _mainAudioService.changeMute(), _effectAudioService.changeMute(), ]); } int get diamonds { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); return currentLevel - 1; } void showReward({required BuildContext context, required PrizeEntity prize}) { showRewardDialog(context: context, prize: prize); } /// ------------Event Calls------------ FutureOr _getLevelListEvent( GetLevelListEvent event, Emitter emit, ) async { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); final localResult = await _getLeveslUseCase(LevelParams()); localResult.fold((data) async { nodeList ..clear() ..addAll(data); try { emit( state.copyWith( getLevelStatus: const BaseComplete(''), chooseLevel: data .firstWhere((e) => e.level?.order == currentLevel) .level, ), ); } catch (e) { emit( state.copyWith( getLevelStatus: const BaseComplete(''), chooseLevel: LevelEntity(), ), ); } add(StartScrollEvent()); }, (error) {}); if (nodeList.isNotEmpty && nodeList.last.nodeType == NodeType.comingSoon) { final remoteResult = await _getLeveslUseCase( LevelParams(forceRemote: true), ); remoteResult.fold((data) { nodeList ..clear() ..addAll(data); }, (error) {}); } } FutureOr _startScrollEvent( StartScrollEvent event, Emitter emit, ) async { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); await Future.delayed(const Duration(seconds: 1)); if (scrollController.hasClients) { if (currentLevel >= 14) { scrollController.animateTo( scrollController.position.maxScrollExtent, duration: const Duration(milliseconds: 500), // Note: 500 seconds is very long. curve: Curves.easeInOut, ); } else if (currentLevel > 8 && currentLevel < 14) { scrollController.animateTo( scrollController.position.maxScrollExtent / 2, duration: const Duration(milliseconds: 500), // Note: 500 seconds is very long. curve: Curves.easeInOut, ); } } } FutureOr _setCurrentLevelEvent( SetCurrentLevelEvent event, Emitter emit, ) async { final String? currentLevel = LocalStorage.readData( key: MyConstants.currentLevel, ); if (currentLevel == null || currentLevel.isEmpty) { await LocalStorage.saveData(key: MyConstants.currentLevel, value: '1'); } add(GetLevelListEvent()); } FutureOr _chooseLevelEvent( ChooseLevelEvent event, Emitter emit, ) { if (event.type != LevelType.unFinished) { emit(state.copyWith(chooseLevel: event.level)); } } }