From 86955617ac1ff681fefb74c3ba1d4b97aede6cc3 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Mon, 4 Nov 2024 08:35:41 +0200 Subject: [PATCH 1/6] add counting down and disable btn for 1 min --- .../screens/identity_verification_screen.dart | 124 +++++++++++++----- 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index a2c21595d..5edc5e1df 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:core'; import 'package:flutter/material.dart'; @@ -59,6 +60,25 @@ class _IdentityVerificationScreenState double spending = 0.0; + int emailCountdown = 60; + Timer? emailTimer; + ValueNotifier countdownNotifier = ValueNotifier(-1); + + void startEmailCountdown() { + emailCountdown = 60; + countdownNotifier.value = emailCountdown; + + emailTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (emailCountdown > 0) { + emailCountdown--; + countdownNotifier.value = emailCountdown; + } else { + countdownNotifier.value = -1; + timer.cancel(); + } + }); + } + setEmailVerified() { if (mounted) { setState(() { @@ -100,11 +120,17 @@ class _IdentityVerificationScreenState Globals().phoneVerified.addListener(setPhoneVerified); Globals().identityVerified.addListener(setIdentityVerified); Globals().hidePhoneButton.addListener(setHidePhoneVerify); - checkPhoneStatus(); getUserValues(); } + @override + void dispose() { + emailTimer?.cancel(); + countdownNotifier.dispose(); + super.dispose(); + } + checkPhoneStatus() { if (Globals().smsSentOn + (Globals().smsMinutesCoolDown * 60 * 1000) > DateTime.now().millisecondsSinceEpoch) { @@ -667,7 +693,7 @@ class _IdentityVerificationScreenState right: const BorderSide(color: Colors.grey, width: 0.5), bottom: const BorderSide(color: Colors.grey, width: 0.5), top: const BorderSide(color: Colors.grey, width: 0.5))), - height: 75, + height: 90, width: MediaQuery.of(context).size.width * 100, child: Row( children: [ @@ -738,6 +764,35 @@ class _IdentityVerificationScreenState ) ], ), + if (step == 1) + ValueListenableBuilder( + valueListenable: countdownNotifier, + builder: (context, countdownValue, child) { + if (countdownValue > 0) { + return Row( + children: [ + Expanded( + child: Text( + 'Verification email sent, retry in $countdownValue second${countdownValue == 1 ? '' : 's'}', + overflow: TextOverflow.clip, + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + fontWeight: + FontWeight.bold, + color: Theme.of(context) + .colorScheme + .warning), + ), + ), + ], + ); + } else { + return Container(); + } + }, + ), step == 2 && Globals().hidePhoneButton.value == true ? const SizedBox( @@ -766,35 +821,42 @@ class _IdentityVerificationScreenState ]))), Globals().hidePhoneButton.value == true && step == 2 ? Container() - : ElevatedButton( - onPressed: () async { - switch (step) { - // Verify email - case 1: - { - verifyEmail(); - } - break; - - // Verify phone - case 2: - { - await verifyPhone(); - } - break; - - // Verify identity - case 3: - { - await verifyIdentityProcess(); - } - break; - default: - {} - break; - } - }, - child: const Text('Verify')) + : ValueListenableBuilder( + valueListenable: countdownNotifier, + builder: (context, countdownValue, child) { + return ElevatedButton( + onPressed: countdownValue > 0 + ? null + : () async { + switch (step) { + // Verify email + case 1: + { + startEmailCountdown(); + verifyEmail(); + } + break; + + // Verify phone + case 2: + { + await verifyPhone(); + } + break; + + // Verify identity + case 3: + { + await verifyIdentityProcess(); + } + break; + default: + {} + break; + } + }, + child: const Text('Verify')); + }) ], ), const Padding(padding: EdgeInsets.only(right: 10)), From 6c2850c0ee4d262592784028b1d398cef7386056 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 24 Nov 2024 14:48:03 +0200 Subject: [PATCH 2/6] disable changing email if counter is active --- app/lib/screens/identity_verification_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index d2cf887eb..c12d7078f 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -821,7 +821,7 @@ class _IdentityVerificationScreenState Widget currentPhaseWidget(step, text, icon) { return GestureDetector( onTap: () async { - if (step == 1) { + if (step == 1 && countdownNotifier.value == -1) { return _changeEmailDialog(false); } @@ -1767,7 +1767,7 @@ class _IdentityVerificationScreenState return; } - if (email == '') { + if (email == '' && countdownNotifier.value == -1) { return _changeEmailDialog(true); } From 39b2a7f965795163bcf7cc519343420f335e9c08 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 27 Nov 2024 17:18:34 +0200 Subject: [PATCH 3/6] start counter when changing email from dialog --- app/lib/screens/identity_verification_screen.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index c12d7078f..83374286a 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -1680,6 +1680,7 @@ class _IdentityVerificationScreenState Navigator.pop(context); Navigator.pop(dialogContext); resendEmailDialog(context); + startEmailCountdown(); setState(() {}); } catch (e) { From 0908945492e1d55901b66bba63e10527a458ec57 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Thu, 28 Nov 2024 13:54:18 +0200 Subject: [PATCH 4/6] fix counter bug --- app/lib/screens/identity_verification_screen.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index 83374286a..51bf7add0 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -86,6 +86,10 @@ class _IdentityVerificationScreenState if (mounted) { setState(() { emailVerified = Globals().emailVerified.value; + if (emailVerified){ + countdownNotifier.value = -1; + emailTimer?.cancel(); + } }); } } From 8683ebaa585f49d8b647b29734f776c1ca19fd61 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 1 Dec 2024 12:48:42 +0200 Subject: [PATCH 5/6] handle counter to countinue even if user changed the page --- app/lib/helpers/globals.dart | 3 ++ .../screens/identity_verification_screen.dart | 46 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/app/lib/helpers/globals.dart b/app/lib/helpers/globals.dart index c02dc1db1..f930fda34 100644 --- a/app/lib/helpers/globals.dart +++ b/app/lib/helpers/globals.dart @@ -72,6 +72,9 @@ class Globals { int smsMinutesCoolDown = 5; int spendingLimit = 0; + int emailSentOn = 0; + int emailMinutesCoolDown = 1; + ValueNotifier hidePhoneButton = ValueNotifier(false); static final Globals _singleton = Globals._internal(); diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index 51bf7add0..1ba87be0b 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -68,13 +68,22 @@ class _IdentityVerificationScreenState ValueNotifier countdownNotifier = ValueNotifier(-1); void startEmailCountdown() { - emailCountdown = 60; + Globals().emailSentOn = DateTime.now().millisecondsSinceEpoch; + + emailCountdown = Globals().emailMinutesCoolDown * 60; + countdownNotifier.value = emailCountdown; + emailTimer?.cancel(); + emailTimer = Timer.periodic(const Duration(seconds: 1), (timer) { - if (emailCountdown > 0) { - emailCountdown--; - countdownNotifier.value = emailCountdown; + int currentTime = DateTime.now().millisecondsSinceEpoch; + int lockedUntil = + Globals().emailSentOn + (Globals().emailMinutesCoolDown * 60 * 1000); + int timeLeft = ((lockedUntil - currentTime) / 1000).round(); + + if (timeLeft > 0) { + countdownNotifier.value = timeLeft; } else { countdownNotifier.value = -1; timer.cancel(); @@ -82,11 +91,37 @@ class _IdentityVerificationScreenState }); } + void resumeEmailCountdownIfNeeded() { + int currentTime = DateTime.now().millisecondsSinceEpoch; + int lockedUntil = + Globals().emailSentOn + (Globals().emailMinutesCoolDown * 60 * 1000); + int timeLeft = ((lockedUntil - currentTime) / 1000).round(); + + if (timeLeft > 0) { + emailCountdown = timeLeft; + countdownNotifier.value = emailCountdown; + + emailTimer?.cancel(); + + emailTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (emailCountdown > 0) { + emailCountdown--; + countdownNotifier.value = emailCountdown; + } else { + countdownNotifier.value = -1; + timer.cancel(); + } + }); + } else { + countdownNotifier.value = -1; + } + } + setEmailVerified() { if (mounted) { setState(() { emailVerified = Globals().emailVerified.value; - if (emailVerified){ + if (emailVerified) { countdownNotifier.value = -1; emailTimer?.cancel(); } @@ -129,6 +164,7 @@ class _IdentityVerificationScreenState Globals().hidePhoneButton.addListener(setHidePhoneVerify); checkPhoneStatus(); getUserValues(); + resumeEmailCountdownIfNeeded(); } @override From d25bf490298a357a3e17320fd8b4da5fd437a087 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Mon, 2 Dec 2024 11:30:02 +0200 Subject: [PATCH 6/6] improve counter function to startOrResumeEmailCountdown --- .../screens/identity_verification_screen.dart | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/app/lib/screens/identity_verification_screen.dart b/app/lib/screens/identity_verification_screen.dart index 1ba87be0b..29b030417 100644 --- a/app/lib/screens/identity_verification_screen.dart +++ b/app/lib/screens/identity_verification_screen.dart @@ -67,36 +67,17 @@ class _IdentityVerificationScreenState Timer? emailTimer; ValueNotifier countdownNotifier = ValueNotifier(-1); - void startEmailCountdown() { - Globals().emailSentOn = DateTime.now().millisecondsSinceEpoch; - - emailCountdown = Globals().emailMinutesCoolDown * 60; - - countdownNotifier.value = emailCountdown; - - emailTimer?.cancel(); - - emailTimer = Timer.periodic(const Duration(seconds: 1), (timer) { - int currentTime = DateTime.now().millisecondsSinceEpoch; - int lockedUntil = - Globals().emailSentOn + (Globals().emailMinutesCoolDown * 60 * 1000); - int timeLeft = ((lockedUntil - currentTime) / 1000).round(); - - if (timeLeft > 0) { - countdownNotifier.value = timeLeft; - } else { - countdownNotifier.value = -1; - timer.cancel(); - } - }); - } - - void resumeEmailCountdownIfNeeded() { + void startOrResumeEmailCountdown({bool startNew = false}) { int currentTime = DateTime.now().millisecondsSinceEpoch; int lockedUntil = Globals().emailSentOn + (Globals().emailMinutesCoolDown * 60 * 1000); int timeLeft = ((lockedUntil - currentTime) / 1000).round(); + if (startNew) { + Globals().emailSentOn = currentTime; + timeLeft = Globals().emailMinutesCoolDown * 60; + } + if (timeLeft > 0) { emailCountdown = timeLeft; countdownNotifier.value = emailCountdown; @@ -104,9 +85,13 @@ class _IdentityVerificationScreenState emailTimer?.cancel(); emailTimer = Timer.periodic(const Duration(seconds: 1), (timer) { - if (emailCountdown > 0) { - emailCountdown--; - countdownNotifier.value = emailCountdown; + int currentTime = DateTime.now().millisecondsSinceEpoch; + int lockedUntil = Globals().emailSentOn + + (Globals().emailMinutesCoolDown * 60 * 1000); + int remainingTime = ((lockedUntil - currentTime) / 1000).round(); + + if (remainingTime > 0) { + countdownNotifier.value = remainingTime; } else { countdownNotifier.value = -1; timer.cancel(); @@ -164,7 +149,7 @@ class _IdentityVerificationScreenState Globals().hidePhoneButton.addListener(setHidePhoneVerify); checkPhoneStatus(); getUserValues(); - resumeEmailCountdownIfNeeded(); + startOrResumeEmailCountdown(); } @override @@ -1041,7 +1026,8 @@ class _IdentityVerificationScreenState // Verify email case 1: { - startEmailCountdown(); + startOrResumeEmailCountdown( + startNew: true); verifyEmail(); } break; @@ -1720,7 +1706,7 @@ class _IdentityVerificationScreenState Navigator.pop(context); Navigator.pop(dialogContext); resendEmailDialog(context); - startEmailCountdown(); + startOrResumeEmailCountdown(startNew: true); setState(() {}); } catch (e) {