import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/status/base_status.dart'; import 'package:hadi_hoda_flutter/core/utils/my_localization.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/button/my_blue_button.dart'; import 'package:hadi_hoda_flutter/core/widgets/error/error_state.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/app/presentation/bloc/app_bloc.dart'; import 'package:hadi_hoda_flutter/features/app/presentation/bloc/app_event.dart'; import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_event.dart'; import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_bloc.dart'; import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_event.dart'; import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_state.dart'; import 'package:wheel_chooser/wheel_chooser.dart'; import '../../../../core/widgets/animations/rotation_anim.dart'; import '../../domain/entity/language_entity.dart'; class LanguagePage extends StatefulWidget { const LanguagePage({super.key}); @override State createState() => _LanguagePageState(); } class _LanguagePageState extends State { final controller = FixedExtentScrollController(initialItem: 50); bool _isEnabled = false; LanguageEntity? _selectedLanguage; @override void initState() { super.initState(); _selectedLanguage = context.read().state.selectedLanguage ?? const LanguageEntity( code: 'en', title: '', displayName: 'English (English', ); context.read().add(const GetLanguagesEvent()); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Container( height: context.heightScreen, width: context.widthScreen, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0XFF00154C), Color(0XFF150532)], ), image: DecorationImage( image: const AssetImage(MyAssets.pattern), scale: 3, repeat: ImageRepeat.repeat, colorFilter: ColorFilter.mode( Colors.white.withValues(alpha: 0.2), BlendMode.srcIn, ), ), ), child: BlocConsumer( listener: (context, state) async { if (state.languages.isNotEmpty && !_isEnabled) { int targetIndex = 0; if (state.selectedLanguage != null) { targetIndex = state.languages.indexWhere( (l) => l.code == state.selectedLanguage!.code, ); if (targetIndex == -1) targetIndex = 0; } await Future.delayed(const Duration(milliseconds: 50)); if (controller.hasClients) { await controller.animateToItem( targetIndex, duration: const Duration(seconds: 1), curve: Curves.easeOutCirc, ); if (state.selectedLanguage == null && context.mounted) { context.read().add( SelectLanguageEvent(state.languages[targetIndex]), ); } } setState(() => _isEnabled = true); } }, builder: (context, state) { if (state.getLanguagesStatus is BaseLoading) { return Center(child: _loading(context)); } if (state.getLanguagesStatus is BaseError) { return Padding( padding: EdgeInsets.symmetric( vertical: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s16, horizontal: 60, ), child: ErrorState( onTap: () { context.read().add(const GetLanguagesEvent()); }, ), ); } final double itemSize = setSize(context: context, mobile: 45, tablet: 60) ?? 45; final selectStyle = MYTextStyle.titr1.copyWith( // Keep same size as before (WheelChooser.choices) fontSize: itemSize * 0.34, color: Colors.white, ); final unSelectStyle = MYTextStyle.titr1.copyWith( fontSize: itemSize * 0.34, color: Colors.white.withValues(alpha: 0.5), ); return Padding( padding: EdgeInsets.only( left: setSize(context: context, mobile: 50, tablet: 0.3.w) ?? 0, right: setSize(context: context, mobile: 50, tablet: 0.3.w) ?? 0, bottom: MySpaces.s40 + MediaQuery.paddingOf(context).bottom, top: 60, ), child: Column( children: [ _title(context), const SizedBox(height: 72), Expanded( child: ShaderMask( shaderCallback: (rect) { return const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0x00FFF7FA), Color(0x1AFFF7FA), Color(0xFFFFFFFF), Color(0x1AFEFCFD), Color(0x00FEFCFD), ], ).createShader(rect); }, child: Stack( children: [ Center( child: Container( width: double.infinity, alignment: Alignment.centerLeft, height: itemSize, padding: const EdgeInsets.symmetric( horizontal: 18, ), decoration: BoxDecoration( color: Colors.white.withValues(alpha: .2), borderRadius: BorderRadius.circular(12), ), child: Transform.translate( offset: (state .selectedLanguage ?.displayName .length ?? 0) > 21 ? const Offset(-10, 0) : Offset.zero, child: const MyImage(image: MyAssets.check), ), ), ), WheelChooser.custom( controller: controller, datas: null, startPosition: null, perspective: 0.00000001, listWidth: double.infinity, listHeight: double.infinity, itemSize: itemSize, isInfinite: true, onValueChanged: (position) { if (state.languages.isEmpty) return; final pos = position is int ? position : int.tryParse(position.toString()) ?? 0; final index = ((pos % state.languages.length) + state.languages.length) % state.languages.length; final lang = state.languages[index]; setState(() { _selectedLanguage = lang; }); }, children: state.languages.map((lang) { final isSelected = _selectedLanguage?.code == lang.code; return Center( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 36, ), child: MediaQuery( data: MediaQuery.of(context).copyWith( textScaler: const TextScaler.linear(1.5), ), child: AutoSizeText( lang.displayName, textAlign: TextAlign.center, maxLines: 2, minFontSize: 10, stepGranularity: 0.5, overflow: TextOverflow.ellipsis, style: isSelected ? selectStyle : unSelectStyle, ), ), ), ); }).toList(), ), ], ), ), ), const SizedBox(height: 72), _btn(context, state), ], ), ); }, ), ), ); } Widget _loading(BuildContext context) { return RotationAnim( child: MyImage( image: MyAssets.loading, size: setSize(context: context, mobile: 110, tablet: 145), ), ); } Widget _title(BuildContext context) { return Row( spacing: MySpaces.s10, mainAxisAlignment: MainAxisAlignment.center, children: [ const MyImage(image: MyAssets.lang, size: 28), AutoSizeText( context.translate.select_language, minFontSize: 12, maxFontSize: 20, maxLines: 1, textAlign: TextAlign.center, style: MYTextStyle.titr0.copyWith(color: const Color(0XFF847AC4)), ), ], ); } Widget _btn(BuildContext context, LanguageState state) { return MyBlueButton( onTap: (_isEnabled && _selectedLanguage != null) ? () async { context.read().add( SelectLanguageEvent(_selectedLanguage!), ); final downloadBloc = context.read(); // 1. Cancel any previous downloads. downloadBloc.add(CancelDownloadEvent()); // 2. Update App Locale context.read().add( ChangeLocaleEvent(_selectedLanguage!.locale), ); await Future.delayed(const Duration(milliseconds: 80)); final lastDownloadedLevel = await downloadBloc .lastDownloadedLevel(); if (!context.mounted) return; if (lastDownloadedLevel >= MyConstants.firstDownloadBatchCount) { context.goNamed(Routes.homePage); } else { context.read().add( const StartDownloadEvent( toLevel: MyConstants.firstDownloadBatchCount, ), ); context.goNamed( Routes.downloadPage, extra: const DownloadPageConfig( downloadToLevel: MyConstants.firstDownloadBatchCount, redirectTo: Routes.homePage, ), ); } } : null, title: context.translate.select, ); } }