Firebase 如何在flatter中为电话号码验证创建倒计时

Firebase 如何在flatter中为电话号码验证创建倒计时,firebase,flutter,Firebase,Flutter,我是个新手。我有一个Flitter和firebase认证系统,用户将输入他们的电话号码,并向他们发送otp。然后,我想实现一个功能,其中将显示otp超时的倒计时,以便用户可以在超时后再次发送otp 目前,我的代码完美地将otp发送给用户,我想要实现的是如何显示otp超时的计时器倒计时 这是我的密码 LoginScreen.dart class LoginScreen extends StatefulWidget { @override _LoginScreenState createSt

我是个新手。我有一个Flitter和firebase认证系统,用户将输入他们的电话号码,并向他们发送otp。然后,我想实现一个功能,其中将显示otp超时的倒计时,以便用户可以在超时后再次发送otp

目前,我的代码完美地将otp发送给用户,我想要实现的是如何显示otp超时的计时器倒计时

这是我的密码

LoginScreen.dart

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  TextEditingController _controller = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Phone Auth'),
      ),
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Column(children: [
              Container(
                margin: EdgeInsets.only(top: 60),
                child: Center(
                  child: Text(
                    'Phone Authentication',
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 28),
                  ),
                ),
              ),
              Container(
                margin: EdgeInsets.only(top: 40, right: 10, left: 10),
                child: TextField(
                  decoration: InputDecoration(
                    hintText: 'Phone Number',
                    prefix: Padding(
                      padding: EdgeInsets.all(4),
                      child: Text('+234'),
                    ),
                  ),
                  maxLength: 10,
                  keyboardType: TextInputType.number,
                  controller: _controller,
                ),
              )
            ]),
            Container(
              margin: EdgeInsets.all(10),
              width: double.infinity,
              child: FlatButton(
                color: Colors.blue,
                onPressed: () {
                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) => OTPScreen(_controller.text)));
                },
                child: Text(
                  'Next',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}
class LoginScreen扩展StatefulWidget{
@凌驾
_LoginsScreenState createState()=>\u LoginsScreenState();
}
类_LoginScreenState扩展状态{
TextEditingController _controller=TextEditingController();
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“电话认证”),
),
正文:SingleChildScrollView(
子:列(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:[
栏(儿童:[
容器(
页边距:仅限边缘集(顶部:60),
儿童:中心(
子:文本(
“电话认证”,
样式:TextStyle(fontWeight:fontWeight.bold,fontSize:28),
),
),
),
容器(
页边距:仅限边集(顶部:40,右侧:10,左侧:10),
孩子:TextField(
装饰:输入装饰(
hintText:'电话号码',
前缀:填充(
填充:边缘设置。全部(4),
子项:文本(“+234”),
),
),
最大长度:10,
键盘类型:TextInputType.number,
控制器:_控制器,
),
)
]),
容器(
保证金:所有(10),
宽度:double.infinity,
孩子:扁平按钮(
颜色:颜色,蓝色,
已按下:(){
导航器.of(上下文).push(MaterialPageRoute(
生成器:(context)=>OTPScreen(_controller.text));
},
子:文本(
“下一个”,
样式:TextStyle(颜色:Colors.white),
),
),
)
],
),
),
);
}
}
OTP过程筛选

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';

class OTPScreen extends StatefulWidget {
  final String phoneNumber;

  OTPScreen({@required this.phoneNumber});
  @override
  _OTPScreenState createState() => _OTPScreenState();
}

class _OTPScreenState extends State<OTPScreen> {
  final GlobalKey<ScaffoldState> _scaffoldkey = GlobalKey<ScaffoldState>();
  String _verificationCode;
  final TextEditingController _pinPutController = TextEditingController();
  final FocusNode _pinPutFocusNode = FocusNode();
  final BoxDecoration pinPutDecoration = BoxDecoration(
    color: const Color.fromRGBO(43, 46, 66, 1),
    borderRadius: BorderRadius.circular(10.0),
    border: Border.all(
      color: const Color.fromRGBO(126, 203, 224, 1),
    ),
  );
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldkey,
      appBar: AppBar(
        title: Text(
          'OTP Verification',
          style: TextStyle(fontWeight: FontWeight.normal),
        ),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Container(
              margin: EdgeInsets.only(top: 35),
              child: Column(
                children: [
                  Text(
                    "Code is sent to " + widget.phoneNumber,
                    style: TextStyle(
                      fontSize: 20,
                      color: Color(0xFF818181),
                    ),
                  ),
                  SizedBox(
                    height: 20,
                  ),
                  Text(
                    'Enter your 6-digit code',
                    style: TextStyle(fontSize: 20),
                  ),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(30.0),
              child: PinPut(
                fieldsCount: 6,
                textStyle: const TextStyle(fontSize: 25.0, color: Colors.white),
                eachFieldWidth: 40.0,
                eachFieldHeight: 55.0,
                focusNode: _pinPutFocusNode,
                controller: _pinPutController,
                submittedFieldDecoration: pinPutDecoration,
                selectedFieldDecoration: pinPutDecoration,
                followingFieldDecoration: pinPutDecoration,
                pinAnimationType: PinAnimationType.fade,
                onSubmit: (pin) async {
                  try {
                    await FirebaseAuth.instance
                        .signInWithCredential(PhoneAuthProvider.credential(
                            verificationId: _verificationCode, smsCode: pin))
                        .then((value) async {
                      if (value.user != null) {
                        Navigator.pushAndRemoveUntil(
                            context,
                            MaterialPageRoute(builder: (context) => Home()),
                            (route) => false);
                      }
                    });
                  } catch (e) {
                    FocusScope.of(context).unfocus();
                    _scaffoldkey.currentState
                        .showSnackBar(SnackBar(content: Text('invalid OTP')));
                  }
                },
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 30),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  TextButton(
                      onPressed: () {
                        //Check if timeout has elaspsed, if true then enable button for user to click
                      },
                      child: Text(
                        'Resend Code',
                        style: TextStyle(color: Color(0xFF81C784)),
                      )),
                  InkWell(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => SetupProfile()));
                    },
                    borderRadius: BorderRadius.circular(33),
                    child: Image.asset(
                      'assets/images/forward.png',
                      height: 50,
                      width: 50,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  _verifyPhone() async {
    await FirebaseAuth.instance.verifyPhoneNumber(
        phoneNumber: '+234${widget.phoneNumber}',
        verificationCompleted: (PhoneAuthCredential credential) async {
          await FirebaseAuth.instance
              .signInWithCredential(credential)
              .then((value) async {
            if (value.user != null) {
              Navigator.pushAndRemoveUntil(
                  context,
                  MaterialPageRoute(builder: (context) => Home()),
                  (route) => false);
            }
          });
        },
        verificationFailed: (FirebaseAuthException e) {
          print(e.message);
        },
        codeSent: (String verficationID, int resendToken) {
          setState(() {
            _verificationCode = verficationID;
          });
        },
        codeAutoRetrievalTimeout: (String verificationID) {
          setState(() {
            _verificationCode = verificationID;
          });
        },
        timeout: Duration(seconds: 120));
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
     _verifyPhone();
  }
}
import'package:firebase_auth/firebase_auth.dart';
进口“包装:颤振/cupertino.dart”;
进口“包装:颤振/材料.省道”;
导入“包装:pinput/pin_-put/pin_-put.dart”;
类OTPScreen扩展StatefulWidget{
最终字符串电话号码;
OTPScreen({@required this.phoneNumber});
@凌驾
_OTPScreenState createState()=>\u OTPScreenState();
}
类_OTPScreenState扩展状态{
最终GlobalKey _scaffoldkey=GlobalKey();
字符串验证代码;
最终TextEditingController _pinPutController=TextEditingController();
最终FocusNode_pinPutFocusNode=FocusNode();
最终BoxDecoration pinPutDecoration=BoxDecoration(
颜色:const color.fromRGBO(43,46,66,1),
边界半径:边界半径。圆形(10.0),
边界:边界(
颜色:常量颜色。来自RGBO(1262032241),
),
);
@凌驾
小部件构建(构建上下文){
返回脚手架(
钥匙:_scaffoldkey,
appBar:appBar(
标题:正文(
“OTP验证”,
样式:文本样式(fontWeight:fontWeight.normal),
),
),
正文:SingleChildScrollView(
子:列(
儿童:[
容器(
页边距:仅限边缘集(顶部:35),
子:列(
儿童:[
正文(
“代码被发送到”+widget.phoneNumber,
样式:TextStyle(
尺寸:20,
颜色:颜色(0xFF818181),
),
),
大小盒子(
身高:20,
),
正文(
'输入您的6位代码',
样式:TextStyle(字体大小:20),
),
],
),
),
填充物(
填充:常数边集全部(30.0),
孩子:平普特(
现场侦察:6,
textStyle:const textStyle(fontSize:25.0,颜色:Colors.white),
每个字段宽度:40.0,
每个场地高度:55.0,
focusNode:_pinPutFocusNode,
控制器:_pinPutController,
提交的现场装饰:Pinput装饰,
selectedFieldDecoration:pinPutDecoration,
现场装饰:平普特装饰,
pinAnimationType:pinAnimationType.fade,
onSubmit:(pin)异步{
试一试{
等待FirebaseAuth.instance
.signInWithCredential(PhoneAuthProvider.credential(
验证ID:_验证代码,smsCode:pin)
.then((值)异步{
如果(value.user!=null){
Navigator.pushandremove直到(
上下文
MaterialPage路由(生成器:(上下文)=>Home()),
(路由)=>错误);
}
});
}捕获(e){
(上下文)的焦点范围。取消焦点();
_scaffoldkey.currentState
.showSnackBar(SnackBar(内容:文本(“无效OTP”));
}
},
),
),
填充物(
衬垫