import 'package:flutter/material.dart'; import 'package:pinput/pinput.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; class OtpVerificationBottomSheet extends StatefulWidget { final String otpMethod; final Function(String otp) onOtpVerified; final VoidCallback? onResend; final VoidCallback? onChangeMethod; const OtpVerificationBottomSheet({ Key? key, required this.otpMethod, required this.onOtpVerified, this.onResend, this.onChangeMethod, }) : super(key: key); @override State createState() => _OtpVerificationBottomSheetState(); } class _OtpVerificationBottomSheetState extends State { final ValueNotifier _timerNotifier = ValueNotifier("2:00"); bool _canResend = false; @override void initState() { super.initState(); _startTimer(); } void _startTimer() { int seconds = 120; // 2 minutes _canResend = false; Future.doWhile(() async { await Future.delayed(const Duration(seconds: 1)); if (!mounted) return false; seconds--; if (seconds <= 0) { _timerNotifier.value = "0:00"; _canResend = true; return false; } final minutes = seconds ~/ 60; final secs = seconds % 60; _timerNotifier.value = "$minutes:${secs.toString().padLeft(2, '0')}"; return true; }); } @override void dispose() { _timerNotifier.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final defaultPinTheme = PinTheme( width: 51.toScreenWidth, height: 63.toScreenHeight, textStyle: TextStyle(fontSize: 24, color: AppColor.headingTextColor(context)), decoration: BoxDecoration( color: AppColor.background(context), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColor.border2Color(context)), ), ); return WillPopScope( onWillPop: () async => false, // Prevent dismiss by back button child: SingleChildScrollView( padding: EdgeInsets.zero, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ InfoTextWidget( label: 'OTP has been sent to your ${widget.otpMethod.toLowerCase()}', isMsg: true, showEmptyValue: true, ), Center( child: Pinput( length: 4, defaultPinTheme: defaultPinTheme, focusedPinTheme: defaultPinTheme.copyWith( decoration: defaultPinTheme.decoration?.copyWith( border: Border.all(color: AppColor.primary10), ), ), onCompleted: (pin) async { // Call the verification callback widget.onOtpVerified(pin); }, ), ).paddingOnly(top: 24, bottom: 24), Row( children: [ InfoTextWidget(label: 'Resend in', isMsg: true, showEmptyValue: true), 6.width, ValueListenableBuilder( valueListenable: _timerNotifier, builder: (context, value, _) { return InfoTextWidget(label: value, isMsg: true, showEmptyValue: true); }, ), 6.width, InkWell( onTap: _canResend ? () { if (widget.onResend != null) { widget.onResend!(); _startTimer(); } } : null, child: Text( 'Resend', style: TextStyle( color: _canResend ? AppColor.primary10 : AppColor.white50, fontWeight: FontWeight.w500, fontSize: 12.toScreenWidth, decorationColor: _canResend ? AppColor.primary10 : AppColor.white50, decoration: TextDecoration.underline, ), ), ), ], ), ], ).toShadowContainer(context), 16.height, Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 4, children: [ InfoHeader16Widget('Having trouble receiving OTP?'), InkWell( onTap: () { Navigator.pop(context); if (widget.onChangeMethod != null) { widget.onChangeMethod!(); } }, child: Text( 'Check out other methods', style: TextStyle( color: AppColor.primary10, fontSize: 16.toScreenWidth, fontWeight: FontWeight.w500, decoration: TextDecoration.underline, decorationColor: AppColor.primary10, ), ), ), ], ), ], ), ), ); } }