import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get/get.dart'; import 'package:taxglide/consts/app_asstes.dart'; import 'package:taxglide/consts/app_colors.dart'; import 'package:taxglide/consts/comman_button.dart'; import 'package:taxglide/consts/comman_container_auth.dart'; import 'package:taxglide/consts/responsive_helper.dart'; import 'package:taxglide/consts/validation_popup.dart'; import 'package:taxglide/controller/api_contoller.dart'; import 'package:taxglide/view/Main_controller/main_controller.dart'; import 'package:taxglide/consts/app_style.dart'; class MpinSetScreen extends ConsumerStatefulWidget { const MpinSetScreen({super.key}); @override ConsumerState createState() => _MpinSetScreenState(); } class _MpinSetScreenState extends ConsumerState { final ValidationPopup _validationPopup = ValidationPopup(); final int pinLength = 4; final List _controllers = []; final List _focusNodes = []; String pinValue = ''; @override void initState() { super.initState(); _initControllers(); } void _initControllers() { for (var c in _controllers) c.dispose(); for (var f in _focusNodes) f.dispose(); _controllers.clear(); _focusNodes.clear(); pinValue = ''; for (int i = 0; i < pinLength; i++) { _controllers.add(TextEditingController()); _focusNodes.add(FocusNode()); } } @override void dispose() { for (var c in _controllers) c.dispose(); for (var f in _focusNodes) f.dispose(); super.dispose(); } void _handleAction() async { if (pinValue.length != pinLength) { _validationPopup.showErrorMessage(context, "Please enter all 4 digits"); return; } // Call API to set/change PIN await ref.read(changePinProvider.notifier).changePin(pinValue); final state = ref.read(changePinProvider); state.when( data: (result) { if (result['success'] == true) { _validationPopup.showSuccessMessage( context, "MPIN Set Successfully!", ); Future.delayed(const Duration(seconds: 1), () { Get.offAll(() => const MainController()); }); } else { _validationPopup.showErrorMessage( context, result['error'] ?? "Failed to set MPIN. Please try again.", ); } }, loading: () {}, error: (error, stack) { _validationPopup.showErrorMessage( context, "Failed to set MPIN. Please try again.", ); }, ); } void _onPinChange(int index, String value) { if (value.isNotEmpty && index < pinLength - 1) { _focusNodes[index + 1].requestFocus(); } if (value.isEmpty && index > 0) { _focusNodes[index - 1].requestFocus(); } setState(() { pinValue = _controllers.map((c) => c.text).join(); }); } @override Widget build(BuildContext context) { final pinState = ref.watch(changePinProvider); final isLoading = pinState is AsyncLoading; final r = ResponsiveUtils(context); final logoWidth = r.getValue(mobile: 120, tablet: 141, desktop: 160); final logoHeight = r.getValue(mobile: 85, tablet: 100, desktop: 115); final titleFontSize = r.fontSize(mobile: 26, tablet: 32, desktop: 36); final subtitleFontSize = r.fontSize(mobile: 13, tablet: 14, desktop: 15); final boxWidth = r.getValue(mobile: 57, tablet: 60, desktop: 68); final boxHeight = r.getValue(mobile: 57, tablet: 56, desktop: 64); final pinFontSize = r.fontSize(mobile: 22, tablet: 28, desktop: 32); final boxMargin = r.getValue(mobile: 5, tablet: 6, desktop: 8); final boxRadius = r.getValue(mobile: 5, tablet: 6, desktop: 8); final spacingSM = r.spacing(mobile: 20, tablet: 20, desktop: 24); final spacingLG = r.spacing(mobile: 50, tablet: 50, desktop: 50); return Scaffold( body: Stack( children: [ Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Color(0xFFFFF8F0), Color(0xFFEBC894), Color(0xFFE8DAF2), Color(0xFFB49EF4), ], stops: [0.0, 0.3, 0.6, 1.0], ), ), ), SingleChildScrollView( child: SizedBox( height: r.screenHeight, child: Center( child: CommonContainerAuth( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( AppAssets.taxgildelogoauth, width: logoWidth, height: logoHeight, fit: BoxFit.contain, ), SizedBox(height: spacingSM), Text( "Set New MPIN", textAlign: TextAlign.center, style: AppTextStyles.semiBold.copyWith( fontSize: titleFontSize, color: AppColors.authheading, ), ), SizedBox(height: spacingSM), Text( "Set a 4-digit security PIN for your account", textAlign: TextAlign.center, style: AppTextStyles.semiBold.copyWith( fontSize: subtitleFontSize, color: AppColors.authleading, ), ), SizedBox(height: spacingLG), Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(pinLength, (index) { bool isFilled = _controllers[index].text.isNotEmpty; return Container( margin: EdgeInsets.symmetric(horizontal: boxMargin), width: boxWidth, height: boxHeight, decoration: BoxDecoration( color: isFilled ? AppColors.commanbutton : Colors.white, borderRadius: BorderRadius.circular(boxRadius), border: Border.all(color: const Color(0xFFDFDFDF)), boxShadow: [ BoxShadow( color: const Color(0xFFBDBDBD).withOpacity(0.25), blurRadius: 7, offset: const Offset(0, 1), ), ], ), child: Center( child: KeyboardListener( focusNode: FocusNode(), onKeyEvent: (event) { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.backspace) { if (_controllers[index].text.isEmpty && index > 0) { _focusNodes[index - 1].requestFocus(); } } }, child: TextField( controller: _controllers[index], focusNode: _focusNodes[index], textAlign: TextAlign.center, keyboardType: TextInputType.number, maxLength: 1, obscureText: true, enabled: !isLoading, style: TextStyle( fontFamily: "Gilroy", fontWeight: FontWeight.w400, fontSize: pinFontSize, color: isFilled ? Colors.white : Colors.black, ), decoration: const InputDecoration( counterText: '', border: InputBorder.none, ), onChanged: (value) => _onPinChange(index, value), ), ), ), ); }), ), SizedBox(height: spacingLG), isLoading ? const CircularProgressIndicator() : CommanButton( text: "Set PIN", onPressed: _handleAction, ), ], ), ), ), ), ), ], ), ); } }