From d7eff24d2993ceea46fe0f963f7aba99cbf5f641 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Wed, 9 Mar 2022 16:42:01 +0330 Subject: [PATCH] D1APP-112 Otp --- lib/services/network/request_helper.dart | 1 + .../authentication/authentication_state.dart | 27 ++- .../authentication/screens/verification.dart | 176 ++++++++++++------ 3 files changed, 146 insertions(+), 58 deletions(-) diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index e0fe29f..53a76ec 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -17,6 +17,7 @@ class RequestHelper { static const String updateProfilePhoto = _baseUserUrl + '/profile/photo'; static const String checkUsername = _baseUserUrl + '/CheckUsername'; static const String updateProfile = _baseUserUrl + '/profile/edit'; + static const String otp = _baseUserUrl + '/otp'; static String bookmarks({String? type}) => _baseUserUrl + '/marked/${type ?? ''}'; diff --git a/lib/views/authentication/authentication_state.dart b/lib/views/authentication/authentication_state.dart index 7efa3ba..3ad97b6 100644 --- a/lib/views/authentication/authentication_state.dart +++ b/lib/views/authentication/authentication_state.dart @@ -10,7 +10,6 @@ class AuthenticationState extends CoreProvier { int _currentPageIndex = 0; String username = ''; String password = ''; - String verificationCode = ''; set currentPageIndex(int value) { _currentPageIndex = value; @@ -57,4 +56,30 @@ class AuthenticationState extends CoreProvier { } return null; } + + Future sendOtpToken() async { + final service = RequestService(RequestHelper.otp + '?username=$username'); + await service.httpGet(); + } + + Future verifyOtpToken(String token) async { + appState = AppState.isolatedBusy; + + final service = RequestService(RequestHelper.otp, body: { + 'code': token, + 'username': username, + }); + await service.post(); + appState = AppState.idle; + if (service.isSuccess) { + currentPageIndex++; + return true; + } + ActionSheetUtils.showAlert(AlertData( + message: service.isSuccess + ? service.result['message'] + : 'کد وارد شده صحیح نمی‌باشد', + )); + return false; + } } diff --git a/lib/views/authentication/screens/verification.dart b/lib/views/authentication/screens/verification.dart index 80bfeef..1a359fe 100644 --- a/lib/views/authentication/screens/verification.dart +++ b/lib/views/authentication/screens/verification.dart @@ -1,5 +1,8 @@ +import 'dart:async'; + import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/providers/user_provider.dart'; import 'package:didvan/views/authentication/authentication_state.dart'; import 'package:didvan/views/authentication/widgets/authentication_layout.dart'; import 'package:didvan/views/widgets/didvan/button.dart'; @@ -8,69 +11,128 @@ import 'package:flutter/material.dart'; import 'package:pin_code_fields/pin_code_fields.dart'; import 'package:provider/provider.dart'; -class Verification extends StatelessWidget { +class Verification extends StatefulWidget { const Verification({Key? key}) : super(key: key); + @override + State createState() => _VerificationState(); +} + +class _VerificationState extends State { + Timer? _timer; + int _secondsRemaining = 119; + + bool _isResendButtonEnabled = false; + + @override + void initState() { + final state = context.read(); + if (state.username == '') { + final user = context.read().user; + state.username = user.phoneNumber; + } + Future.delayed( + Duration.zero, + state.sendOtpToken, + ); + _handleTimer(); + super.initState(); + } + @override Widget build(BuildContext context) { final AuthenticationState state = context.read(); - return AuthenticationLayout( - appBarTitle: 'تغییر رمز عبور', - children: [ - DidvanText( - 'کد 6 رقمی ارسال شده به موبایل', - style: Theme.of(context).textTheme.subtitle2, - fontWeight: FontWeight.normal, - ), - const SizedBox( - height: 8, - ), - DidvanText( - state.username, - style: Theme.of(context).textTheme.subtitle1, - ), - const SizedBox( - height: 8, - ), - DidvanText( - 'را وارد کنید:', - style: Theme.of(context).textTheme.subtitle2, - fontWeight: FontWeight.normal, - ), - const SizedBox( - height: 24, - ), - Directionality( - textDirection: TextDirection.ltr, - child: PinCodeTextField( - keyboardType: TextInputType.number, - animationType: AnimationType.scale, - pinTheme: PinTheme( - fieldHeight: 48, - fieldWidth: 48, - inactiveColor: Theme.of(context).colorScheme.border, - activeFillColor: Theme.of(context).colorScheme.primary, - activeColor: Theme.of(context).colorScheme.primary, - borderRadius: DesignConfig.lowBorderRadius, - borderWidth: 1, - shape: PinCodeFieldShape.box, - ), - appContext: context, - length: 6, - onChanged: (value) => state.verificationCode = value, + return WillPopScope( + onWillPop: () async { + _timer?.cancel(); + return true; + }, + child: AuthenticationLayout( + appBarTitle: 'تغییر رمز عبور', + children: [ + DidvanText( + 'کد 6 رقمی ارسال شده به موبایل', + style: Theme.of(context).textTheme.subtitle2, + fontWeight: FontWeight.normal, ), - ), - const Spacer(), - DidvanButton( - onPressed: () { - state.currentPageIndex++; - }, - title: 'ارسال مجدد کد', - ), - const SizedBox( - height: 48, - ), - ], + const SizedBox( + height: 8, + ), + DidvanText( + state.username, + style: Theme.of(context).textTheme.subtitle1, + ), + const SizedBox( + height: 8, + ), + DidvanText( + 'را وارد کنید:', + style: Theme.of(context).textTheme.subtitle2, + fontWeight: FontWeight.normal, + ), + const SizedBox( + height: 24, + ), + Directionality( + textDirection: TextDirection.ltr, + child: PinCodeTextField( + keyboardType: TextInputType.number, + animationType: AnimationType.scale, + cursorColor: Theme.of(context).colorScheme.text, + pinTheme: PinTheme( + fieldHeight: 48, + fieldWidth: 48, + selectedColor: Theme.of(context).colorScheme.primary, + inactiveColor: Theme.of(context).colorScheme.border, + activeFillColor: Theme.of(context).colorScheme.primary, + activeColor: Theme.of(context).colorScheme.primary, + borderRadius: DesignConfig.lowBorderRadius, + borderWidth: 1, + shape: PinCodeFieldShape.box, + ), + appContext: context, + length: 6, + onCompleted: (value) async { + final result = await state.verifyOtpToken(value); + if (result) { + _timer?.cancel(); + } + }, + onChanged: (value) {}, + ), + ), + const Spacer(), + DidvanButton( + enabled: _isResendButtonEnabled, + onPressed: () { + _handleTimer(); + state.sendOtpToken(); + }, + title: !_isResendButtonEnabled + ? '$_secondsRemaining ثانیه دیگر' + : 'ارسال مجدد کد', + ), + const SizedBox( + height: 48, + ), + ], + ), ); } + + Future _handleTimer() async { + _timer?.cancel(); + _isResendButtonEnabled = false; + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + setState(() { + _secondsRemaining -= 1; + if (_secondsRemaining == 0) { + _isResendButtonEnabled = true; + _secondsRemaining = 129; + _timer?.cancel(); + } + }); + }); + setState(() {}); + } }