import 'dart:async'; import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/enum/auth_method_types.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'package:flutter/material.dart'; import '../../config/config.dart'; import 'package:cloudflare_turnstile/cloudflare_turnstile.dart'; class SMSOTP { final AuthMethodTypes type; final mobileNo; final Function onSuccess; final Function onFailure; final context; int remainingTime = 600; SMSOTP( this.context, this.type, this.mobileNo, this.onSuccess, this.onFailure, ); final verifyAccountForm = GlobalKey(); TextEditingController digit1 = TextEditingController(text: ""); TextEditingController digit2 = TextEditingController(text: ""); TextEditingController digit3 = TextEditingController(text: ""); TextEditingController digit4 = TextEditingController(text: ""); Map verifyAccountFormValue = { 'digit1': '', 'digit2': '', 'digit3': '', 'digit4': '', }; final focusD1 = FocusNode(); final focusD2 = FocusNode(); final focusD3 = FocusNode(); final focusD4 = FocusNode(); String errorMsg = ''; late ProjectViewModel projectProvider; String displayTime = ''; bool isClosed = false; final TurnstileController _controller = TurnstileController(); final TurnstileOptions _options = TurnstileOptions( size: TurnstileSize.normal, theme: TurnstileTheme.light, refreshExpired: TurnstileRefreshExpired.manual, language: 'en', retryAutomatically: false, ); String? _token; displayDialog(BuildContext context) async { double dialogWidth = MediaQuery.of(context).size.width * 0.90; double dialogInputWidth = (dialogWidth / 4) - (SizeConfig.isWidthLarge ? SizeConfig.getWidthMultiplier(width: dialogWidth) * 4.5 : 20); double dialogHeight = SizeConfig.isHeightVeryShort ? MediaQuery.of(context).size.height * 0.60 : MediaQuery.of(context).size.height * 0.50; return showDialog( context: context, builder: (ctx) => Center( child: Container( color: Colors.white, height: dialogHeight, width: dialogWidth, child: Material( color: Colors.white, child: SingleChildScrollView( child: Center( child: Container( color: Colors.white, child: StatefulBuilder(builder: (context, setState) { if (displayTime == '') { startTimer(setState); } return Center( child: FractionallySizedBox( widthFactor: 0.9, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 2, ), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon( type == AuthMethodTypes.SMS ? DoctorApp.verify_sms_1 : DoctorApp.verify_whtsapp, size: SizeConfig.getHeightMultiplier(height: dialogHeight) * 9, color: Color(0xFF2B353E), ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( icon: Icon(Icons.close), color: Color(0xFF2B353E), iconSize: SizeConfig.getHeightMultiplier(height: dialogHeight) * 15, onPressed: () { this.isClosed = true; Navigator.pop(context); this.onFailure(); }, ) ], ) ]), SizedBox( height: SizeConfig.getHeightMultiplier(height: dialogHeight) * (SizeConfig.isHeightVeryShort ? 10 : 5), ), Padding( padding: EdgeInsets.only(top: 5, right: 5), child: AppText( TranslationBase.of(context).verificationMessage + ' XXXXXX' + mobileNo.toString().substring(mobileNo.toString().length - 3), textAlign: TextAlign.start, fontWeight: FontWeight.w700, letterSpacing: -0.48, color: Color(0xFF2B353E), fontSize: SizeConfig.getTextMultiplierBasedOnWidth(width: dialogWidth) * 3.5, //14, maxLines: 2, )), Form( key: verifyAccountForm, child: Padding( padding: EdgeInsets.only(top: SizeConfig.getHeightMultiplier(height: dialogHeight) * 2), child: Directionality( textDirection: TextDirection.ltr, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( width: dialogInputWidth, height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), child: TextFormField( textInputAction: TextInputAction.next, style: buildTextStyle(), autofocus: true, maxLength: 1, controller: digit1, textAlign: TextAlign.center, keyboardType: TextInputType.number, decoration: buildInputDecoration(context), onSaved: (val) {}, // validator: validateCodeDigit, onFieldSubmitted: (_) { FocusScope.of(context).requestFocus(focusD2); }, onChanged: (val) { if (val.length == 1) { FocusScope.of(context).requestFocus(focusD2); verifyAccountFormValue['digit1'] = val.trim(); checkValue(); } }, validator: validateCodeDigit), ), Container( width: dialogInputWidth, height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), child: TextFormField( focusNode: focusD2, textInputAction: TextInputAction.next, maxLength: 1, controller: digit2, textAlign: TextAlign.center, style: buildTextStyle(), keyboardType: TextInputType.number, decoration: buildInputDecoration(context), onSaved: (val) {}, onFieldSubmitted: (_) { FocusScope.of(context).requestFocus(focusD3); }, onChanged: (val) { if (val.length == 1) { FocusScope.of(context).requestFocus(focusD3); verifyAccountFormValue['digit2'] = val.trim(); checkValue(); } }, validator: validateCodeDigit // validator: validateCodeDigit ), ), Container( margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), width: dialogInputWidth, height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, child: TextFormField( focusNode: focusD3, textInputAction: TextInputAction.next, maxLength: 1, controller: digit3, textAlign: TextAlign.center, style: buildTextStyle(), keyboardType: TextInputType.number, decoration: buildInputDecoration(context), onSaved: (val) {}, onFieldSubmitted: (_) { FocusScope.of(context).requestFocus(focusD4); }, onChanged: (val) { if (val.length == 1) { FocusScope.of(context).requestFocus(focusD4); verifyAccountFormValue['digit3'] = val.trim(); checkValue(); } }, validator: validateCodeDigit // validator: validateCodeDigit )), Container( margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), width: dialogInputWidth, height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, child: TextFormField( focusNode: focusD4, maxLength: 1, textAlign: TextAlign.center, style: buildTextStyle(), controller: digit4, keyboardType: TextInputType.number, decoration: buildInputDecoration(context), onFieldSubmitted: (_) { FocusScope.of(context).requestFocus(focusD4); }, onChanged: (val) { if (val.length == 1) { verifyAccountFormValue['digit4'] = val.trim(); checkValue(); } }, validator: validateCodeDigit), ), ], )), ), ), Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ AppText( TranslationBase.of(context).validationMessage + ' ', textAlign: TextAlign.start, fontWeight: FontWeight.w700, letterSpacing: -0.48, color: Color(0xFF2B353E), fontSize: SizeConfig.getTextMultiplierBasedOnWidth(width: dialogWidth) * 3.5, ), AppText( displayTime, color: Colors.red, textAlign: TextAlign.start, fontWeight: FontWeight.bold, fontSize: SizeConfig.getTextMultiplierBasedOnWidth(width: dialogWidth) * 3.5, ) ]), SizedBox(height: 10,), Column(children: [ CloudflareTurnstile( siteKey: '0x4AAAAAAAkmbvEy63pcxBBt', baseUrl: BASE_URL, options: _options, controller: _controller, onTokenReceived: (token) { setState(() { print("Cloudflare token: $token"); _token = token; checkValue(); }); }, // onTokenRecived: (token) { // setState(() { // print("Cloudflare token: $token"); // _token = token; // }); // }, onTokenExpired: () {}, // mode: TurnstileMode.managed, // errorBuilder: (context, error) { // return Text(error.message); // }, ), ],), ], ), ), ); })), ), ), ), ), ), ); } TextStyle buildTextStyle() { return TextStyle( fontSize: SizeConfig.textMultiplier! * 2.5, ); } InputDecoration buildInputDecoration(BuildContext context) { return InputDecoration( counterText: " ", enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10)), borderSide: BorderSide(color: Colors.grey[300]!), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.grey[300]!), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Colors.grey[300]!), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Theme.of(context).colorScheme.error), ), ); } // ignore: missing_return String? validateCodeDigit(value) { if (value.isEmpty) { return ''; } else if (value.length == 3) { print(value); } return null; } checkValue() async { if (verifyAccountForm.currentState!.validate() && _token !=null) { // if (digit1.text.isNotEmpty && digit2.text.isNotEmpty && digit3.text.isNotEmpty && digit4.text.isNotEmpty) { onSuccess(digit1.text.toString() + digit2.text.toString() + digit3.text.toString() + digit4.text.toString()); this.isClosed = true; } } getSecondsAsDigitalClock(int inputSeconds) { var sec_num = int.parse(inputSeconds.toString()); // don't forget the second param var hours = (sec_num / 3600).floor(); var minutes = ((sec_num - hours * 3600) / 60).floor(); var seconds = sec_num - hours * 3600 - minutes * 60; var minutesString = ""; var secondsString = ""; minutesString = minutes < 10 ? "0" + minutes.toString() : minutes.toString(); secondsString = seconds < 10 ? "0" + seconds.toString() : seconds.toString(); return minutesString + ":" + secondsString; } startTimer(setState) { this.remainingTime--; setState(() { displayTime = this.getSecondsAsDigitalClock(this.remainingTime); }); Future.delayed(Duration(seconds: 1), () { if (this.remainingTime > 0) { if (isClosed == false) { startTimer(setState); } } else { Navigator.pop(context); } }); } }