// ignore_for_file: use_build_context_synchronously import 'dart:async'; import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:go_router/go_router.dart'; import 'package:hoshan/core/routes/route_generator.dart'; import 'package:hoshan/core/utils/date_time.dart'; import 'package:hoshan/data/model/auth/auth_screens_enum.dart'; import 'package:hoshan/ui/screens/auth/cubit/auth_screens_cubit.dart'; import 'package:hoshan/ui/screens/auth/register/bloc/register_bloc.dart'; import 'package:hoshan/ui/screens/auth/verification/bloc/verification_bloc.dart'; import 'package:hoshan/ui/screens/auth/verification/sms_retriever_impl.dart'; import 'package:hoshan/ui/screens/splash/cubit/user_info_cubit.dart'; import 'package:hoshan/ui/theme/colors.dart'; import 'package:hoshan/ui/theme/text.dart'; import 'package:hoshan/ui/widgets/components/button/loading_button.dart'; import 'package:pinput/pinput.dart'; import 'package:smart_auth/smart_auth.dart'; import 'package:string_validator/string_validator.dart'; ValueNotifier seconds = ValueNotifier(120); class VerificationScreen extends StatefulWidget { const VerificationScreen({super.key}); @override State createState() => _VerificationScreenState(); } class _VerificationScreenState extends State { ValueNotifier error = ValueNotifier(false); ValueNotifier readOnly = ValueNotifier(false); Timer? _timer; late final defaultPinTheme = PinTheme( textStyle: AppTextStyles.headline5 .copyWith(color: Theme.of(context).colorScheme.primary), width: 56, height: 56, decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.gray.defaultShade))); final errorPinTheme = PinTheme( textStyle: AppTextStyles.headline5.copyWith(color: AppColors.red.defaultShade), width: 56, height: 56, decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.red.defaultShade))); void startTimer() { _timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { seconds.value = seconds.value - 1; if (seconds.value == 0) { timer.cancel(); error.value = true; readOnly.value = true; return; } }); } @override void initState() { startTimer(); super.initState(); } @override void dispose() { super.dispose(); _timer?.cancel(); } @override Widget build(BuildContext context) { return BlocConsumer( listener: (context, state) async { if (state is VerificationLoading) { readOnly.value = true; } else { readOnly.value = false; } if (state is VerificationFail) { error.value = true; } else if (state is VerificationSuccess) { if (state.isNew) { context.read().changeState(AuthScreens.code); } else { await context.read().getUserInfo(); context.go(Routes.giftCredit); } } }, builder: (context, state) { return ValueListenableBuilder( valueListenable: readOnly, builder: (context, readOnlyVal, _) { return Column( children: [ Text( 'کد تایید شش رقمی به ${context.read().username.isEmail ? 'ایمیل شما' : 'شماره شما'} ارسال شد.', textDirection: TextDirection.rtl, style: AppTextStyles.body5.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface), ), Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: () => context .read() .changeState(AuthScreens.mobile), child: Text( 'تغییر ${context.read().username.isEmail ? 'ایمیل' : 'شماره همراه'} ', style: AppTextStyles.body5.copyWith( color: Theme.of(context).colorScheme.primary), ), ), const SizedBox( width: 4, ), Icon( Icons.edit, size: 16, color: Theme.of(context).colorScheme.primary, ) ], ), ), Padding( padding: const EdgeInsets.symmetric( vertical: 24.0, horizontal: 16), child: ValueListenableBuilder( valueListenable: error, builder: (context, errVal, _) { return Column( children: [ Pinput( smsRetriever: !kIsWeb && !Platform.isIOS ? SmsRetrieverImpl(SmartAuth.instance) : null, readOnly: readOnlyVal, forceErrorState: errVal, defaultPinTheme: defaultPinTheme, focusedPinTheme: defaultPinTheme.copyBorderWith( border: Border.all( color: Theme.of(context) .colorScheme .primary)), submittedPinTheme: defaultPinTheme.copyBorderWith( border: Border.all( color: Theme.of(context) .colorScheme .primary)), errorPinTheme: errorPinTheme, keyboardType: TextInputType.number, length: 6, autofocus: true, closeKeyboardWhenCompleted: true, onChanged: (value) { error.value = false; }, onCompleted: (String value) { final number = context .read() .username; final isNew = context.read().isNew; context.read().add( LoginWithOTP( number: number, otp: value, isNew: isNew)); }, ), const SizedBox( height: 12, ), if (errVal) Text( seconds.value == 0 ? 'دوباره تلاش کنید' : context.read().state is VerificationFail && (state as VerificationFail) .errorServer ? "خطا از طرف سرور" : '!کد وارد شده اشتباه است', style: errorPinTheme.textStyle, ), const SizedBox( height: 12, ), if (state is VerificationLoading || state is VerificationSuccess) SpinKitThreeBounce( color: Theme.of(context).colorScheme.primary, size: 32, ) ], ); })), Padding( padding: const EdgeInsets.symmetric( vertical: 18.0, horizontal: 16), child: readOnlyVal && state is! VerificationLoading ? BlocConsumer( listener: (context, state) { if (state is RegisterSuccess) { readOnly.value = false; error.value = false; seconds.value = 120; startTimer(); } }, builder: (context, state) { return LoadingButton( width: MediaQuery.sizeOf(context).width, height: 48, radius: 100, loading: state is RegisterLoading, onPressed: () async { context.read().add(LoginUser( phoneNumber: context .read() .username)); }, child: Text( 'ارسال مجدد کد', style: AppTextStyles.body4 .copyWith(color: Colors.white), )); }, ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'تا دریافت مجدد کد', style: AppTextStyles.body4.copyWith( color: Theme.of(context).colorScheme.primary), ), ValueListenableBuilder( valueListenable: seconds, builder: (context, secVal, _) { return Text( ' ${DateTimeUtils.getTimeFromDuration(secVal)}', style: AppTextStyles.body4.copyWith( color: Theme.of(context) .colorScheme .primary)); }), const SizedBox( width: 4, ), Icon( CupertinoIcons.clock, size: 16, color: Theme.of(context).colorScheme.primary, ) ], ), ) ], ); }); }, ); } }