· 4 years ago · Jun 11, 2021, 06:58 PM
1// Modules and components
2import 'dart:async';
3import 'dart:convert';
4import 'package:[project/path/]app_bar.dart';
5import 'package:alertify/alertify.dart';
6import 'package:flutter/cupertino.dart';
7import 'package:flutter/material.dart';
8import 'package:sms_autofill/sms_autofill.dart';
9import 'package:http/http.dart';
10import 'package:[project/path/]l10n.dart';
11// Redirects
12import 'package:[project/path/]next_page.dart';
13// Data libs
14import 'package:[project/path/]globals.dart' as globals;
15import 'package:[project/path/]utils.dart' as utils;
16
17
18class TokenOTP extends StatefulWidget {
19 @override
20 _TokenOTP createState() => _TokenOTPState();
21}
22
23class _TokenOTP extends State<TokenOTP> {
24 // Controllers
25 TextEditingController tokenController;
26 // UI Data
27 int _otpCodeLength = 6;
28 bool _isLoadingButton = true;
29 bool _enableButton = false;
30 String _otpCode = "";
31 final interval = const Duration(seconds: 1);
32 final int timerMaxSeconds = 60;
33 int currentSeconds = 0;
34 bool runTimer = true;
35 // Context deps
36 final _scaffoldKey = GlobalKey<ScaffoldState>();
37 Locale _userLocale;
38
39 String get timerText =>
40 "${((timerMaxSeconds - currentSeconds) ~/ 60).toString().padLeft(2, '0')}:" +
41 "${((timerMaxSeconds - currentSeconds) % 60).toString().padLeft(2, '0')}s";
42
43 /* Framework overrides */
44 @override
45 void initState() {
46 super.initState();
47 startTimeout();
48 utils.getSignatureCode();
49 }
50
51 @override
52 void didChangeDependencies() {
53 final newLocale = Localizations.localeOf(this.context);
54
55 if (newLocale != _userLocale) {
56 _userLocale = newLocale;
57 }
58 super.didChangeDependencies();
59 }
60
61 /* Page logic */
62 startTimeout([int milliseconds]) {
63 var duration = interval;
64 Timer.periodic(duration, (timer) {
65 setState(() {
66 print(timer.tick);
67 if (!runTimer) {
68 timer.cancel();
69 print("Timer cancelado!");
70 _isLoadingButton = false;
71 _enableButton = true;
72 currentSeconds = 0;
73 } else {
74 currentSeconds = timer.tick;
75 if (timer.tick >= timerMaxSeconds) {
76 timer.cancel();
77 _isLoadingButton = false;
78 _enableButton = true;
79 }
80 }
81 });
82 });
83 }
84
85 _onOtpCallBack(String otpCode) async {
86 print("optCode.lenght: ${otpCode.length.toString()} == ${this._otpCodeLength}");
87
88 FocusScope.of(context).requestFocus(new FocusNode());
89
90 setState(() {
91 this._otpCode = otpCode;
92 this._isLoadingButton = false;
93 });
94
95 validateToken();
96 }
97
98 void validateToken() async {
99 try {
100 // CODE TO MAKE REQUEST TO INTERNAL API
101 if ((res.statusCode == 200) && (/* INTERNAL API CHECK */true)) {
102 // CODE TO SAVE SOME DATA FROM API
103 if (_token == this._otpCode.toUpperCase()) {
104 Navigator.push(
105 context, MaterialPageRoute(builder: (context) => NextPage()));
106 } else {
107 _enableButton = true;
108 _isLoadingButton = false;
109 runTimer = false;
110 currentSeconds = 0;
111 }
112 } else {
113 _enableButton = true;
114 _isLoadingButton = false;
115 runTimer = false;
116 currentSeconds = 0;
117 }
118 } catch (error) {
119 await utils.reportError(error);
120 }
121 }
122
123 _onSubmitOtp() {
124 setState(() {
125 _isLoadingButton = true;
126 _enableButton = false;
127 runTimer = true;
128 });
129 startTimeout(timerMaxSeconds);
130 sendToken();
131 }
132
133 void sendToken() async {
134 try {
135 // CODE TO MAKE REQUEST TO INTERNAL API
136 } catch (error) {
137 await utils.reportError(error);
138 }
139 }
140
141 /* Widgets */
142 @override
143 Widget build(BuildContext context) {
144 return Scaffold(
145 key: _scaffoldKey,
146 appBar: AdviceAppBar(
147 child: AppBar(
148 title: Text("Page title!"),
149 automaticallyImplyLeading: true,
150 backgroundColor: Colors.blueGrey,
151 ),
152 ),
153 body: Padding(
154 padding: const EdgeInsets.all(30.0),
155 child: Center(
156 child: Column(
157 mainAxisSize: MainAxisSize.min,
158 mainAxisAlignment: MainAxisAlignment.center,
159 children: <Widget>[
160 Text("Info text!",
161 textAlign: TextAlign.center,
162 style: TextStyle(
163 fontSize: 17,
164 )),
165 SizedBox(
166 height: 32,
167 ),
168 PinFieldAutoFill(
169 decoration: BoxLooseDecoration(
170 textStyle: TextStyle(fontSize: 15),
171 strokeColorBuilder: PinListenColorBuilder(Colors.green[200], Colors.black),
172 bgColorBuilder: PinListenColorBuilder(Colors.blueGrey[100], Colors.white),
173 gapSpace: 8,
174 radius: Radius.circular(6)
175 ),
176 codeLength: _otpCodeLength,
177 controller: tokenController,
178 onCodeChanged: (code) => code.length == _otpCodeLength ? _onOtpCallBack(code) : null,
179 onCodeSubmitted: (code) => code.length == _otpCodeLength ? _onOtpCallBack(code) : null,
180 ),
181 SizedBox(
182 height: 32,
183 ),
184 Container(
185 width: double.maxFinite,
186 child: MaterialButton(
187 disabledTextColor: Colors.red,
188 onPressed: _enableButton ? _onSubmitOtp : null,
189 child: _setUpButtonChild(),
190 color: Colors.blue,
191 disabledColor: Colors.blue[100],
192 enableFeedback: true,
193 ),
194 ),
195 AnimatedOpacity(
196 opacity: (currentSeconds < timerMaxSeconds) ? 1.0 : 0.0,
197 duration: Duration(milliseconds: 0),
198 child: Row(
199 mainAxisSize: MainAxisSize.min,
200 children: <Widget>[
201 Icon(Icons.timer),
202 SizedBox(
203 width: 5,
204 ),
205 Text("${timerText} has elapsed.",
206 softWrap: true)
207 ],
208 ),
209 ),
210 ],
211 ),
212 ),
213 ),
214 );
215 }
216
217 Widget _setUpButtonChild() {
218 if (_isLoadingButton) {
219 return Container(
220 width: 19,
221 height: 19,
222 child: CircularProgressIndicator(
223 valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
224 ),
225 );
226 } else {
227 return Text(
228 "Send new token!",
229 style: TextStyle(color: Colors.white),
230 );
231 }
232 }
233}
234