import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.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/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/screen_size.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/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/level_widget.dart'; class LevelBloc extends Bloc { /// ------------constructor------------ LevelBloc( this._getLeveslUseCase, this._mainAudioService, this._effectAudioService, ) : super(const LevelState()) { volumeStream = _mainAudioService.volumeStream(); on(_getLevelListEvent); on(_setCurrentLevelEvent); on(_startScrollEvent); on(_chooseLevelEvent); } @override Future close() { scrollController.dispose(); return super.close(); } /// ------------UseCases------------ final GetLevelsUseCase _getLeveslUseCase; /// ------------Variables------------ final List locationList = [ LevelLocation(bottom: 0.13.h, left: 0.2.w, index: 0), LevelLocation(bottom: 0.25.h, left: 0.43.w, index: 1), LevelLocation(bottom: 0.35.h, left: 0.22.w, index: 2), LevelLocation(bottom: 0.5.h, left: 0.35.w, index: 3), LevelLocation(bottom: 0.57.h, left: 0.6.w, index: 4), LevelLocation(bottom: 0.65.h, left: 0.8.w, index: 5), LevelLocation(bottom: 0.8.h, left: 0.82.w, index: 6), LevelLocation(bottom: 1.0.h, left: 0.76.w, index: 7), LevelLocation(bottom: 1.15.h, left: 0.6.w, index: 8), LevelLocation(bottom: 1.2.h, left: 0.3.w, index: 9), LevelLocation(bottom: 1.3.h, left: 0.07.w, index: 10), LevelLocation(bottom: 1.38.h, left: 0.3.w, index: 11), LevelLocation(bottom: 1.44.h, left: 0.55.w, index: 12), LevelLocation(bottom: 1.54.h, left: 0.68.w, index: 13), LevelLocation(bottom: 1.63.h, left: 0.6.w, index: 14), LevelLocation(bottom: 1.75.h, left: 0.63.w, index: 15), LevelLocation(bottom: 1.84.h, left: 0.43.w, index: 16), LevelLocation(bottom: 1.82.h, left: 0.17.w, index: 17), LevelLocation(bottom: 1.96.h, left: 0.05.w, index: 18), LevelLocation(bottom: 2.08.h, left: 0.1.w, index: 19), LevelLocation(bottom: 2.14.h, left: 0.3.w, index: 20), LevelLocation(bottom: 2.24.h, left: 0.35.w, index: 21), LevelLocation(bottom: 2.35.h, left: 0.2.w, index: 22), LevelLocation(bottom: 2.44.h, left: 0.14.w, index: 23), LevelLocation(bottom: 2.55.h, left: 0.28.w, index: 24), ]; final List levelList = []; late final Stream volumeStream; /// ------------Controllers------------ final ScrollController scrollController = ScrollController(); final AudioService _mainAudioService; final AudioService _effectAudioService; /// ------------Functions------------ void goToQuestionPage(BuildContext context, LevelEntity level){ context.pushReplacementNamed( Routes.questionPage, pathParameters: { 'id': '${level.id}', }, ); } void goToHomePage(BuildContext context){ context.pop(); } 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; } } Future changeMute() async { await Future.wait([ _mainAudioService.changeMute(), _effectAudioService.changeMute(), ]); } /// ------------Api Calls------------ FutureOr _getLevelListEvent(GetLevelListEvent event, Emitter emit) async { final int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', ); await _getLeveslUseCase(LevelParams()).then((value) { value.fold( (data) async { levelList.addAll(data); try { emit(state.copyWith( getLevelStatus: const BaseComplete(''), chooseLevel: data.singleWhere((e) => e.order == currentLevel), )); } catch (e) { emit(state.copyWith( getLevelStatus: const BaseComplete(''), chooseLevel: LevelEntity(), )); } add(StartScrollEvent()); }, (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)); } } }