feat(sms): автоподстановка кода из sms

This commit is contained in:
klockky
2026-07-03 19:07:09 +03:00
parent 9a04ea69c2
commit 7f22ecc643
4 changed files with 69 additions and 0 deletions
+38
View File
@@ -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 '../../../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<CodeConfirmationScreen>
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<CodeConfirmationScreen>
_epoch = api.sessionEpoch;
_stateSub = api.stateStream.listen(_onSessionState);
_startTimer();
_listenForSmsCode();
_shakeController = AnimationController(
vsync: this,
@@ -85,6 +88,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
if (_routeAnimationListener != null) {
_routeAnimation?.removeStatusListener(_routeAnimationListener!);
}
_smsListener.dispose();
_stateSub?.cancel();
_timer?.cancel();
_errorTimer?.cancel();
@@ -137,6 +141,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
_errorMessage = null;
});
_startTimer();
_listenForSmsCode();
showCustomNotification(
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) {
_errorTimer?.cancel();
_shakeController.forward(from: 0);
+8
View File
@@ -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:
+1
View File
@@ -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: