import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; class OTPController extends GetxController { final formKey = GlobalKey(); // Observables final RxString phoneNumber = ''.obs; final RxBool isOTPSent = false.obs; final RxBool isSending = false.obs; final RxBool isResending = false.obs; final RxInt timer = 0.obs; Timer? _countdownTimer; // Text controllers and focus nodes final TextEditingController phoneController = TextEditingController(); final List otpControllers = List.generate(4, (_) => TextEditingController()); final List focusNodes = List.generate(4, (_) => FocusNode()); @override void onInit() { super.onInit(); timer.value = 0; } @override void onClose() { _countdownTimer?.cancel(); phoneController.dispose(); for (final controller in otpControllers) { controller.dispose(); } for (final node in focusNodes) { node.dispose(); } super.onClose(); } static Future _sendOTP(String phone) async { await Future.delayed(const Duration(seconds: 2)); debugPrint('Sending OTP to $phone'); return true; } Future sendOTP() async { final phone = phoneController.text.trim(); if (!_validatePhone(phone)) { showAppSnackbar( title: "Error", message: "Please enter a valid 10-digit mobile number", type: SnackbarType.error, ); return; } if (isSending.value) return; isSending.value = true; final success = await _sendOTP(phone); if (success) { phoneNumber.value = phone; isOTPSent.value = true; _startTimer(); _clearOTPFields(); } else { showAppSnackbar( title: "Error", message: "Failed to send OTP. Please try again.", type: SnackbarType.error, ); } isSending.value = false; } Future onResendOTP() async { if (isResending.value) return; isResending.value = true; _clearOTPFields(); final success = await _sendOTP(phoneNumber.value); if (success) { _startTimer(); } else { showAppSnackbar( title: "Error", message: "Failed to resend OTP. Please try again.", type: SnackbarType.error, ); } isResending.value = false; } void onOTPChanged(String value, int index) { if (value.isNotEmpty) { if (index < otpControllers.length - 1) { focusNodes[index + 1].requestFocus(); } else { focusNodes[index].unfocus(); } } else { if (index > 0) { focusNodes[index - 1].requestFocus(); } } } void verifyOTP() { final enteredOTP = otpControllers.map((c) => c.text).join(); if (enteredOTP.length != otpControllers.length || enteredOTP.contains('')) { showAppSnackbar( title: "Error", message: "Please enter the complete ${otpControllers.length}-digit OTP", type: SnackbarType.error, ); return; } // TODO: Add your OTP verification logic debugPrint('Verifying OTP: $enteredOTP'); } void _clearOTPFields() { for (final controller in otpControllers) { controller.clear(); } focusNodes[0].requestFocus(); } void _startTimer() { timer.value = 60; _countdownTimer?.cancel(); _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (this.timer.value > 0) { this.timer.value--; } else { timer.cancel(); } }); } void resetForChangeNumber() { isOTPSent.value = false; phoneNumber.value = ''; phoneController.clear(); _clearOTPFields(); timer.value = 0; isSending.value = false; isResending.value = false; for (final node in focusNodes) { node.unfocus(); } } bool _validatePhone(String phone) { final regex = RegExp(r'^\d{10}$'); return regex.hasMatch(phone); } }