From 37e320a52b0476946df15d2ebc4659d714c90d8c Mon Sep 17 00:00:00 2001 From: sergejwinston Date: Tue, 7 Apr 2026 02:51:34 +0700 Subject: [PATCH] feat(auth): integrate SmartAuth for SMS code auto-fill and update localization strings --- android/gradle.properties | 4 ++ .../auth/code_confirmation_screen.dart | 65 +++++++++++++++++-- lib/frontend/screens/auth/login_screen.dart | 9 --- lib/l10n/app_en.arb | 15 ++--- lib/l10n/app_localizations.dart | 20 ++---- lib/l10n/app_localizations_en.dart | 18 +++-- lib/l10n/app_localizations_ru.dart | 9 +-- lib/l10n/app_ru.arb | 6 +- pubspec.lock | 8 +++ pubspec.yaml | 1 + 10 files changed, 101 insertions(+), 54 deletions(-) diff --git a/android/gradle.properties b/android/gradle.properties index 492b2f1..398cde8 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -2,3 +2,7 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m android.useAndroidX=true kotlin.incremental=false dev.steenbakker.mobile_scanner.useUnbundled=true +systemProp.socksProxyHost=127.0.0.1 +systemProp.socksProxyPort=10808 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=10808 diff --git a/lib/frontend/screens/auth/code_confirmation_screen.dart b/lib/frontend/screens/auth/code_confirmation_screen.dart index 3840751..21a2194 100644 --- a/lib/frontend/screens/auth/code_confirmation_screen.dart +++ b/lib/frontend/screens/auth/code_confirmation_screen.dart @@ -1,8 +1,10 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:komet/l10n/app_localizations.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:smart_auth/smart_auth.dart'; import '../chats/chat_list_screen.dart'; import 'password_2fa_screen.dart'; import '../../../main.dart'; @@ -26,9 +28,11 @@ class _CodeConfirmationScreenState extends State with TickerProviderStateMixin { final TextEditingController _codeController = TextEditingController(); final FocusNode _focusNode = FocusNode(); + final SmartAuth _smartAuth = SmartAuth.instance; int _timerSeconds = 30; Timer? _timer; Timer? _errorTimer; + bool _isListeningSmsConsent = false; String? _errorMessage; late AnimationController _shakeController; @@ -41,6 +45,7 @@ class _CodeConfirmationScreenState extends State WidgetsBinding.instance.addPostFrameCallback((_) { _focusNode.requestFocus(); }); + _startSmsCodeListener(); _shakeController = AnimationController( vsync: this, @@ -56,10 +61,63 @@ class _CodeConfirmationScreenState extends State ]).animate(CurvedAnimation(parent: _shakeController, curve: Curves.linear)); } + Future _startSmsCodeListener() async { + if (defaultTargetPlatform != TargetPlatform.android) return; + if (_isListeningSmsConsent) return; + + _isListeningSmsConsent = true; + final result = await _smartAuth.getSmsWithUserConsentApi(matcher: r'\d{6}'); + _isListeningSmsConsent = false; + + if (!mounted || !result.hasData) return; + + final receivedCode = result.data?.code; + if (receivedCode == null || receivedCode.isEmpty) return; + + _applyAutoFillCode(receivedCode); + } + + Future _restartSmsCodeListener() async { + if (defaultTargetPlatform != TargetPlatform.android) return; + await _smartAuth.removeUserConsentApiListener(); + _isListeningSmsConsent = false; + await _startSmsCodeListener(); + } + + void _handleCodeChanged(String value) { + setState(() { + if (_errorMessage != null) { + _errorMessage = null; + } + }); + if (value.length == 6) { + _verifyCode(); + } + } + + void _applyAutoFillCode(String rawCode) { + final digitsOnly = rawCode.replaceAll(RegExp(r'\D'), ''); + if (digitsOnly.isEmpty) return; + + final nextCode = digitsOnly.length <= 6 + ? digitsOnly + : digitsOnly.substring(0, 6); + + if (_codeController.text == nextCode) return; + + _codeController.value = TextEditingValue( + text: nextCode, + selection: TextSelection.collapsed(offset: nextCode.length), + ); + + _handleCodeChanged(nextCode); + } + @override void dispose() { _timer?.cancel(); _errorTimer?.cancel(); + unawaited(_smartAuth.removeUserConsentApiListener()); _shakeController.dispose(); _codeController.dispose(); _focusNode.dispose(); @@ -92,6 +150,7 @@ class _CodeConfirmationScreenState extends State void _resendCode() { if (_timerSeconds == 0) { _startTimer(); + unawaited(_restartSmsCodeListener()); } } @@ -206,11 +265,7 @@ class _CodeConfirmationScreenState extends State FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(6), ], - onChanged: (value) { - if (hasError) setState(() => _errorMessage = null); - setState(() {}); - if (value.length == 6) _verifyCode(); - }, + onChanged: _handleCodeChanged, ), ), ), diff --git a/lib/frontend/screens/auth/login_screen.dart b/lib/frontend/screens/auth/login_screen.dart index 579f250..08f74e8 100644 --- a/lib/frontend/screens/auth/login_screen.dart +++ b/lib/frontend/screens/auth/login_screen.dart @@ -795,15 +795,6 @@ class _LoginScreenState extends State { height: 1.4, ), children: [ - TextSpan( - text: l10n.loginTermsIntro, - style: GoogleFonts.inter( - color: cs.onSurface, - fontSize: 14, - height: 1.4, - fontWeight: FontWeight.w400, - ), - ), TextSpan( text: l10n.loginTermsLink, style: GoogleFonts.inter( diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index aa424d8..7ec3f63 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,23 +1,22 @@ { "@@locale": "en", - "loginTitle": "Sign in to Komet", + "loginTitle": "Log in to Komet", "loginSubtitle": "Check your country code and enter your\nphone number.", "loginCountry": "Country", "loginPhoneNumber": "Phone number", "loginPhoneHint": "(000) 000-00-00", "loginOtherSignInMethods": "Other sign-in methods", - "loginTermsIntro": "By continuing, you agree to \n", - "loginTermsLink": "the terms of use", - "loginTermsOfUse": "Terms of use", + "loginTermsLink": "Terms of Use «Komet»", + "loginTermsOfUse": "Terms of Use «Komet»", "loginConfirmPhoneTitle": "Is this the correct number?", "loginEdit": "Change", "loginDone": "Done", - "loginReadTermsNotification": "Please read the terms of use first", + "loginReadTermsNotification": "Please read the Terms of Use «Komet»", "loginSpoofRedacted": "Spoof redaction", "loginProxy": "Proxy", - "loginSignInWithQr": "Sign in with QR code", - "loginSignInWithToken": "Sign in with token", - "loginSignInWithSessionFile": "Sign in with session file", + "loginSignInWithQr": "Log in with QR code", + "loginSignInWithToken": "Log in with token", + "loginSignInWithSessionFile": "Log in with session file", "loginLanguage": "Language", "languageNameRu": "Русский", "languageNameEn": "English", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index b0614d5..67816f8 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -101,7 +101,7 @@ abstract class AppLocalizations { /// No description provided for @loginTitle. /// /// In en, this message translates to: - /// **'Sign in to Komet'** + /// **'Log in to Komet'** String get loginTitle; /// No description provided for @loginSubtitle. @@ -134,22 +134,16 @@ abstract class AppLocalizations { /// **'Other sign-in methods'** String get loginOtherSignInMethods; - /// No description provided for @loginTermsIntro. - /// - /// In en, this message translates to: - /// **'By continuing, you agree to \n'** - String get loginTermsIntro; - /// No description provided for @loginTermsLink. /// /// In en, this message translates to: - /// **'the terms of use'** + /// **'Terms of Use «Komet»'** String get loginTermsLink; /// No description provided for @loginTermsOfUse. /// /// In en, this message translates to: - /// **'Terms of use'** + /// **'Terms of Use «Komet»'** String get loginTermsOfUse; /// No description provided for @loginConfirmPhoneTitle. @@ -173,7 +167,7 @@ abstract class AppLocalizations { /// No description provided for @loginReadTermsNotification. /// /// In en, this message translates to: - /// **'Please read the terms of use first'** + /// **'Please read the Terms of Use «Komet»'** String get loginReadTermsNotification; /// No description provided for @loginSpoofRedacted. @@ -191,19 +185,19 @@ abstract class AppLocalizations { /// No description provided for @loginSignInWithQr. /// /// In en, this message translates to: - /// **'Sign in with QR code'** + /// **'Log in with QR code'** String get loginSignInWithQr; /// No description provided for @loginSignInWithToken. /// /// In en, this message translates to: - /// **'Sign in with token'** + /// **'Log in with token'** String get loginSignInWithToken; /// No description provided for @loginSignInWithSessionFile. /// /// In en, this message translates to: - /// **'Sign in with session file'** + /// **'Log in with session file'** String get loginSignInWithSessionFile; /// No description provided for @loginLanguage. diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 5ddbe9b..3f6e67e 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -9,7 +9,7 @@ class AppLocalizationsEn extends AppLocalizations { AppLocalizationsEn([String locale = 'en']) : super(locale); @override - String get loginTitle => 'Sign in to Komet'; + String get loginTitle => 'Log in to Komet'; @override String get loginSubtitle => @@ -28,13 +28,10 @@ class AppLocalizationsEn extends AppLocalizations { String get loginOtherSignInMethods => 'Other sign-in methods'; @override - String get loginTermsIntro => 'By continuing, you agree to \n'; + String get loginTermsLink => 'Terms of Use «Komet»'; @override - String get loginTermsLink => 'the terms of use'; - - @override - String get loginTermsOfUse => 'Terms of use'; + String get loginTermsOfUse => 'Terms of Use «Komet»'; @override String get loginConfirmPhoneTitle => 'Is this the correct number?'; @@ -46,7 +43,8 @@ class AppLocalizationsEn extends AppLocalizations { String get loginDone => 'Done'; @override - String get loginReadTermsNotification => 'Please read the terms of use first'; + String get loginReadTermsNotification => + 'Please read the Terms of Use «Komet»'; @override String get loginSpoofRedacted => 'Spoof redaction'; @@ -55,13 +53,13 @@ class AppLocalizationsEn extends AppLocalizations { String get loginProxy => 'Proxy'; @override - String get loginSignInWithQr => 'Sign in with QR code'; + String get loginSignInWithQr => 'Log in with QR code'; @override - String get loginSignInWithToken => 'Sign in with token'; + String get loginSignInWithToken => 'Log in with token'; @override - String get loginSignInWithSessionFile => 'Sign in with session file'; + String get loginSignInWithSessionFile => 'Log in with session file'; @override String get loginLanguage => 'Language'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index e63e96d..63d6d7d 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -28,13 +28,10 @@ class AppLocalizationsRu extends AppLocalizations { String get loginOtherSignInMethods => 'Другие способы входа'; @override - String get loginTermsIntro => 'Продолжая, вы соглашаетесь с \n'; + String get loginTermsLink => 'Условия использования «Komet»'; @override - String get loginTermsLink => 'пользовательскими соглашениями'; - - @override - String get loginTermsOfUse => 'Условия использования'; + String get loginTermsOfUse => 'Условия использования «Komet»'; @override String get loginConfirmPhoneTitle => 'Это правильный номер?'; @@ -47,7 +44,7 @@ class AppLocalizationsRu extends AppLocalizations { @override String get loginReadTermsNotification => - 'Сначала прочитайте условия использования'; + 'Сначала прочитайте условия использования «Komet»'; @override String get loginSpoofRedacted => 'Подделка спуфа'; diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index a53ed02..49ded61 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -7,12 +7,12 @@ "loginPhoneHint": "(000) 000-00-00", "loginOtherSignInMethods": "Другие способы входа", "loginTermsIntro": "Продолжая, вы соглашаетесь с \n", - "loginTermsLink": "пользовательскими соглашениями", - "loginTermsOfUse": "Условия использования", + "loginTermsLink": "Условия использования «Komet»", + "loginTermsOfUse": "Условия использования «Komet»", "loginConfirmPhoneTitle": "Это правильный номер?", "loginEdit": "Изменить", "loginDone": "Готово", - "loginReadTermsNotification": "Сначала прочитайте условия использования", + "loginReadTermsNotification": "Сначала прочитайте условия использования «Komet»", "loginSpoofRedacted": "Подделка спуфа", "loginProxy": "Прокси", "loginSignInWithQr": "По QR code", diff --git a/pubspec.lock b/pubspec.lock index 62a257f..acfb34b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -530,6 +530,14 @@ packages: description: flutter source: sdk version: "0.0.0" + 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 0341c9a..7af58b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,7 @@ dependencies: shared_preferences: ^2.5.4 package_info_plus: ^9.0.1 mobile_scanner: ^7.2.0 + smart_auth: ^3.2.0 dev_dependencies: flutter_test: