feat(sms): автоподстановка кода из sms
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:smart_auth/smart_auth.dart';
|
||||||
|
|
||||||
|
typedef SmsCodeCallback = void Function(String code);
|
||||||
|
|
||||||
|
class SmsCodeListener {
|
||||||
|
static const String _matcher = r'\d{6}';
|
||||||
|
|
||||||
|
final SmartAuth _smartAuth = SmartAuth.instance;
|
||||||
|
bool _listening = false;
|
||||||
|
bool _disposed = false;
|
||||||
|
|
||||||
|
bool get _supported => Platform.isAndroid;
|
||||||
|
|
||||||
|
Future<void> start(SmsCodeCallback onCode) async {
|
||||||
|
if (!_supported || _listening || _disposed) return;
|
||||||
|
_listening = true;
|
||||||
|
|
||||||
|
final result = await _smartAuth.getSmsWithUserConsentApi(matcher: _matcher);
|
||||||
|
|
||||||
|
_listening = false;
|
||||||
|
if (_disposed) return;
|
||||||
|
|
||||||
|
final code = result.hasData ? result.requireData.code : null;
|
||||||
|
if (code != null) onCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> cancel() async {
|
||||||
|
if (!_supported) return;
|
||||||
|
await _smartAuth.removeUserConsentApiListener();
|
||||||
|
_listening = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_disposed = true;
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import 'password_2fa_screen.dart';
|
|||||||
import 'registration_screen.dart';
|
import 'registration_screen.dart';
|
||||||
import '../../../backend/api.dart';
|
import '../../../backend/api.dart';
|
||||||
import '../../../core/protocol/packet.dart';
|
import '../../../core/protocol/packet.dart';
|
||||||
|
import '../../../core/utils/sms_code_listener.dart';
|
||||||
import '../../../main.dart';
|
import '../../../main.dart';
|
||||||
import '../../widgets/custom_notification.dart';
|
import '../../widgets/custom_notification.dart';
|
||||||
import '../../widgets/login_success_screen.dart';
|
import '../../widgets/login_success_screen.dart';
|
||||||
@@ -30,6 +31,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
final TextEditingController _codeController = TextEditingController();
|
final TextEditingController _codeController = TextEditingController();
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
final SmsCodeListener _smsListener = SmsCodeListener();
|
||||||
int _timerSeconds = 30;
|
int _timerSeconds = 30;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
Timer? _errorTimer;
|
Timer? _errorTimer;
|
||||||
@@ -59,6 +61,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
_epoch = api.sessionEpoch;
|
_epoch = api.sessionEpoch;
|
||||||
_stateSub = api.stateStream.listen(_onSessionState);
|
_stateSub = api.stateStream.listen(_onSessionState);
|
||||||
_startTimer();
|
_startTimer();
|
||||||
|
_listenForSmsCode();
|
||||||
|
|
||||||
_shakeController = AnimationController(
|
_shakeController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
@@ -85,6 +88,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
if (_routeAnimationListener != null) {
|
if (_routeAnimationListener != null) {
|
||||||
_routeAnimation?.removeStatusListener(_routeAnimationListener!);
|
_routeAnimation?.removeStatusListener(_routeAnimationListener!);
|
||||||
}
|
}
|
||||||
|
_smsListener.dispose();
|
||||||
_stateSub?.cancel();
|
_stateSub?.cancel();
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_errorTimer?.cancel();
|
_errorTimer?.cancel();
|
||||||
@@ -137,6 +141,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
});
|
});
|
||||||
_startTimer();
|
_startTimer();
|
||||||
|
_listenForSmsCode();
|
||||||
showCustomNotification(
|
showCustomNotification(
|
||||||
context,
|
context,
|
||||||
'Соединение восстановлено — выслали новый код',
|
'Соединение восстановлено — выслали новый код',
|
||||||
@@ -194,6 +199,23 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _listenForSmsCode() async {
|
||||||
|
await _smsListener.start((code) {
|
||||||
|
if (!mounted) return;
|
||||||
|
_applyAutoCode(code);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _applyAutoCode(String code) {
|
||||||
|
if (_verifying || _recovering) return;
|
||||||
|
if (_codeController.text == code) return;
|
||||||
|
_codeController.text = code;
|
||||||
|
_codeController.selection = TextSelection.collapsed(offset: code.length);
|
||||||
|
if (_errorMessage != null) _errorMessage = null;
|
||||||
|
setState(() {});
|
||||||
|
if (code.length == 6) _verifyCode();
|
||||||
|
}
|
||||||
|
|
||||||
void _showError(String message) {
|
void _showError(String message) {
|
||||||
_errorTimer?.cancel();
|
_errorTimer?.cancel();
|
||||||
_shakeController.forward(from: 0);
|
_shakeController.forward(from: 0);
|
||||||
|
|||||||
@@ -1322,6 +1322,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.1"
|
version: "0.1.1"
|
||||||
|
smart_auth:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: smart_auth
|
||||||
|
sha256: a536423c50d71e9a311d16027346634d0deadd07dafc5b5606b46719cf6fb2b6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ dependencies:
|
|||||||
media_kit_libs_linux: ^1.2.1
|
media_kit_libs_linux: ^1.2.1
|
||||||
media_kit_libs_macos_video: ^1.1.4
|
media_kit_libs_macos_video: ^1.1.4
|
||||||
sensors_plus: ^7.1.0
|
sensors_plus: ^7.1.0
|
||||||
|
smart_auth: ^3.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user