From 7f22ecc6437f8fdb2bc92a503f2e8db0d22f436c Mon Sep 17 00:00:00 2001 From: klockky Date: Fri, 3 Jul 2026 19:06:54 +0300 Subject: [PATCH] =?UTF-8?q?feat(sms):=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B8=D0=B7=20sms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/utils/sms_code_listener.dart | 38 +++++++++++++++++++ .../auth/code_confirmation_screen.dart | 22 +++++++++++ pubspec.lock | 8 ++++ pubspec.yaml | 1 + 4 files changed, 69 insertions(+) create mode 100644 lib/core/utils/sms_code_listener.dart diff --git a/lib/core/utils/sms_code_listener.dart b/lib/core/utils/sms_code_listener.dart new file mode 100644 index 0000000..130845b --- /dev/null +++ b/lib/core/utils/sms_code_listener.dart @@ -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 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 cancel() async { + if (!_supported) return; + await _smartAuth.removeUserConsentApiListener(); + _listening = false; + } + + void dispose() { + _disposed = true; + cancel(); + } +} diff --git a/lib/frontend/screens/auth/code_confirmation_screen.dart b/lib/frontend/screens/auth/code_confirmation_screen.dart index 49f9c64..57a5db3 100644 --- a/lib/frontend/screens/auth/code_confirmation_screen.dart +++ b/lib/frontend/screens/auth/code_confirmation_screen.dart @@ -6,6 +6,7 @@ import 'password_2fa_screen.dart'; import 'registration_screen.dart'; import '../../../backend/api.dart'; import '../../../core/protocol/packet.dart'; +import '../../../core/utils/sms_code_listener.dart'; import '../../../main.dart'; import '../../widgets/custom_notification.dart'; import '../../widgets/login_success_screen.dart'; @@ -30,6 +31,7 @@ class _CodeConfirmationScreenState extends State with TickerProviderStateMixin { final TextEditingController _codeController = TextEditingController(); final FocusNode _focusNode = FocusNode(); + final SmsCodeListener _smsListener = SmsCodeListener(); int _timerSeconds = 30; Timer? _timer; Timer? _errorTimer; @@ -59,6 +61,7 @@ class _CodeConfirmationScreenState extends State _epoch = api.sessionEpoch; _stateSub = api.stateStream.listen(_onSessionState); _startTimer(); + _listenForSmsCode(); _shakeController = AnimationController( vsync: this, @@ -85,6 +88,7 @@ class _CodeConfirmationScreenState extends State if (_routeAnimationListener != null) { _routeAnimation?.removeStatusListener(_routeAnimationListener!); } + _smsListener.dispose(); _stateSub?.cancel(); _timer?.cancel(); _errorTimer?.cancel(); @@ -137,6 +141,7 @@ class _CodeConfirmationScreenState extends State _errorMessage = null; }); _startTimer(); + _listenForSmsCode(); showCustomNotification( context, 'Соединение восстановлено — выслали новый код', @@ -194,6 +199,23 @@ class _CodeConfirmationScreenState extends State }); } + Future _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) { _errorTimer?.cancel(); _shakeController.forward(from: 0); diff --git a/pubspec.lock b/pubspec.lock index c259997..919aff8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1322,6 +1322,14 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d7c79f2..b61e7b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,6 +80,7 @@ dependencies: media_kit_libs_linux: ^1.2.1 media_kit_libs_macos_video: ^1.1.4 sensors_plus: ^7.1.0 + smart_auth: ^3.2.0 dev_dependencies: flutter_test: