import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/data/common/dio_error_handler.dart'; import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_chicken/features/common/data/model/response/user_info/user_info_model.dart'; import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart'; import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository.dart'; import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart'; import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.dart'; import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart'; import 'package:rasadyar_core/core.dart'; enum AuthType { useAndPass, otp } enum AuthStatus { init } enum OtpStatus { init, sent, verified, reSend } class AuthLogic extends GetxController with GetTickerProviderStateMixin { GlobalKey formKey = GlobalKey(); late AnimationController _textAnimationController; late Animation textAnimation; RxBool showCard = false.obs; RxBool rememberMe = false.obs; Rx> formKeyOtp = GlobalKey().obs; Rx> formKeySentOtp = GlobalKey().obs; Rx usernameController = TextEditingController().obs; Rx passwordController = TextEditingController().obs; Rx phoneOtpNumberController = TextEditingController().obs; Rx otpCodeController = TextEditingController().obs; var captchaController = Get.find(); RxnString phoneNumber = RxnString(null); RxBool isLoading = false.obs; RxBool isDisabled = true.obs; GService gService = Get.find(); TokenStorageService tokenStorageService = Get.find(); Rx authType = AuthType.useAndPass.obs; Rx authStatus = AuthStatus.init.obs; Rx otpStatus = OtpStatus.init.obs; RxnString deviceName = RxnString(null); RxInt secondsRemaining = 120.obs; Timer? _timer; AuthRepository authRepository = diChicken.get(); final Module _module = Get.arguments; @override void onInit() { super.onInit(); _textAnimationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 1200), ) ..repeat(reverse: true, count: 2).whenComplete(() { showCard.value = true; }); textAnimation = CurvedAnimation( parent: _textAnimationController, curve: Curves.easeInOut, ); initUserPassData(); getDeviceModel(); } @override void onClose() { _textAnimationController.dispose(); _timer?.cancel(); super.onClose(); } void startTimer() { _timer?.cancel(); secondsRemaining.value = 120; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (secondsRemaining.value > 0) { secondsRemaining.value--; } else { timer.cancel(); } }); } void stopTimer() { _timer?.cancel(); } String get timeFormatted { final minutes = secondsRemaining.value ~/ 60; final seconds = secondsRemaining.value % 60; return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; } bool _isFormValid() { final isCaptchaValid = captchaController.formKey.currentState?.validate() ?? false; final isFormValid = formKey.currentState?.validate() ?? false; return isCaptchaValid && isFormValid; } Future submitLoginForm() async { if (!_isFormValid()) return; AuthRepository authTmp = diChicken.get(); isLoading.value = true; await safeCall( call: () => authTmp.login( authRequest: { "username": usernameController.value.text, "password": passwordController.value.text, }, ), onSuccess: (result) async { await gService.saveSelectedModule(_module); await tokenStorageService.saveModule(_module); await tokenStorageService.saveAccessToken( _module, result?.accessToken ?? '', ); await tokenStorageService.saveRefreshToken( _module, result?.accessToken ?? '', ); var tmpRoles = result?.role?.where((element) { final allowedRoles = { 'poultryscience', 'steward', 'killhouse', 'provinceinspector', 'cityjahad', 'jahad', 'vetfarm', 'provincesupervisor', 'superadmin', }; final lowerElement = element.toString().toLowerCase().trim(); return allowedRoles.contains(lowerElement); }).toList(); if (tmpRoles?.length==1) { await tokenStorageService.saveRoles(_module, tmpRoles ?? []); } await tokenStorageService.saveRoles(_module, tmpRoles ?? []); if (rememberMe.value) { await tokenStorageService.saveUserPass( _module, usernameController.value.text, passwordController.value.text, ); } authTmp.stewardAppLogin( token: result?.accessToken ?? '', queryParameters: { "mobile": usernameController.value.text, "device_name": deviceName.value, }, ); Get.offAndToNamed(CommonRoutes.role); /* if (tmpRoles!.length > 1) { Get.offAndToNamed(CommonRoutes.role); } else { Get.offAllNamed(StewardRoutes.initSteward); } */ }, onError: (error, stackTrace) { if (error is DioException) { diChicken.get().handle(error); if ((error.type == DioExceptionType.unknown) || (error.type == DioExceptionType.connectionError)) { getUserInfo(usernameController.value.text); } } captchaController.getCaptcha(); }, ); isLoading.value = false; } Future getUserInfo(String value) async { isLoading.value = true; await safeCall( call: () async => await authRepository.getUserInfo(value), onSuccess: (result) async { if (result != null) { await newSetupAuthDI(result.backend ?? ''); await diChicken.allReady(); } }, onError: (error, stackTrace) { if (error is DioException) { diChicken.get().handle(error); } captchaController.getCaptcha(); }, ); isLoading.value = false; } void initUserPassData() { UserLocalModel? userLocalModel = tokenStorageService.getUserLocal( Module.chicken, ); if (userLocalModel?.username != null && userLocalModel?.password != null) { usernameController.value.text = userLocalModel?.username ?? ''; passwordController.value.text = userLocalModel?.password ?? ''; rememberMe.value = true; } } Future getDeviceModel() async { final deviceInfo = DeviceInfoPlugin(); if (Platform.isAndroid) { final info = await deviceInfo.androidInfo; deviceName.value = 'Device:${info.manufacturer} Model:${info.model} version ${info.version.release}'; } else if (Platform.isIOS) { final info = await deviceInfo.iosInfo; deviceName.value = 'Device:${info.utsname.machine} Model:${info.model} version ${info.systemVersion}'; } else {} } }