This commit is contained in:
Dmitry 2025-12-20 22:46:11 +03:00
parent 1bfec9d511
commit 9157706cad
2 changed files with 53 additions and 174 deletions

View file

@ -6,7 +6,6 @@ import 'package:yx_scope_flutter/yx_scope_flutter.dart';
import 'package:mnemo_cards_web_v2/di/app_scope/app_scope_container.dart';
import 'package:mnemo_cards_web_v2/domain/config/api_config_v2.dart';
import 'package:mnemo_cards_web_v2/presentation/pages/auth/sign_in_with_google_button.dart';
import 'package:mnemo_cards_web_v2/presentation/pages/auth/sign_in_with_telegram.dart';
/// Authentication page
@ -23,75 +22,6 @@ class _AuthPageState extends State<AuthPage> {
bool _isLoading = false;
String? _errorMessage;
Future<void> _loginWithGoogle(BuildContext context) async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
// Get router before async operations to avoid context issues
final router = GoRouter.of(context);
try {
final appScope = ScopeProvider.of<AppScopeContainer>(
context,
listen: false,
);
if (appScope == null) {
throw Exception('AppScope not available');
}
// Login via Google
final user = await appScope.authService.loginWithGoogle();
if (!mounted) return;
if (user != null) {
log('Google login successful: ${user.email}', name: 'AuthPage');
// Create UserScope if it doesn't exist
if (appScope.userScopeHolder.scope == null) {
await appScope.userScopeHolder.create();
}
// Update user state and wait for it to complete
await appScope.userScopeHolder.scope!.userStateManager.setUser(user);
// Notify that UserScope has changed
appScope.notifyUserScopeChanged();
// Notify router about auth change
appScope.userScopeHolder.notifyAuthChanged();
// Router will automatically redirect to /home when authentication state changes
// Force router refresh to ensure redirect happens
if (mounted) {
// Small delay to ensure state is fully updated
await Future<void>.delayed(const Duration(milliseconds: 50));
if (mounted && appScope.userScopeHolder.isAuthenticated) {
router.go('/home');
}
}
} else {
setState(() {
_errorMessage = 'Login cancelled';
});
}
} catch (e, s) {
log('Error in Google login', error: e, stackTrace: s, name: 'AuthPage');
if (mounted) {
setState(() {
_errorMessage = 'Login failed: ${e.toString()}';
});
}
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
}
}
Future<void> _onTelegramLoginSuccess(BuildContext context) async {
// Router will automatically redirect to /home when authentication state changes
// No manual navigation needed - let the GoRouter handle the redirect
@ -115,7 +45,7 @@ class _AuthPageState extends State<AuthPage> {
backgroundColor: theme.colorScheme.surface,
appBar: AppBar(
title: Text(
'Login',
'Вход',
style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w700,
),
@ -149,7 +79,7 @@ class _AuthPageState extends State<AuthPage> {
),
const SizedBox(height: 24),
Text(
'Sign in to your account',
'Войдите в свой аккаунт',
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurface,
@ -158,7 +88,7 @@ class _AuthPageState extends State<AuthPage> {
),
const SizedBox(height: 8),
Text(
'Save your progress and sync data',
'Сохраняйте прогресс и синхронизируйте данные',
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurfaceVariant,
@ -205,40 +135,6 @@ class _AuthPageState extends State<AuthPage> {
),
),
],
// Login buttons
// SignInWithGoogleButton(
// onPressed: () => _loginWithGoogle(context),
// isLoading: _isLoading,
// ),
// const SizedBox(height: 24),
// Divider
Row(
children: [
Expanded(
child: Divider(
color: theme.dividerColor,
thickness: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
'OR',
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurfaceVariant,
),
),
),
Expanded(
child: Divider(
color: theme.dividerColor,
thickness: 1,
),
),
],
),
const SizedBox(height: 24),
// Telegram auth code input
SignInWithTelegram(
onLoginSuccess: () => _onTelegramLoginSuccess(context),

View file

@ -34,17 +34,38 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
TelegramAuthCodeStatus? _webCodeStatus;
Timer? _codeStatusTimer;
Timer? _countdownTimer;
Timer? _autoCheckTimer;
DateTime? _codeExpiryTime;
bool _autoLoginAttempted = false;
@override
void initState() {
super.initState();
_telegramCodeController.addListener(_onCodeChanged);
}
@override
void dispose() {
_codeStatusTimer?.cancel();
_countdownTimer?.cancel();
_autoCheckTimer?.cancel();
_telegramCodeController.removeListener(_onCodeChanged);
_telegramCodeController.dispose();
super.dispose();
}
void _onCodeChanged() {
_autoCheckTimer?.cancel();
final code = _telegramCodeController.text.trim();
if (code.length > 4) {
_autoCheckTimer = Timer(const Duration(seconds: 1), () {
if (mounted && _telegramCodeController.text.trim().length > 4) {
_loginWithTelegram();
}
});
}
}
Future<void> _loginWithTelegram({String? codeParam}) async {
final code = codeParam ?? _telegramCodeController.text.trim();
@ -428,29 +449,6 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
}
}
Future<void> _openTelegramBot() async {
final deepLink = Uri.parse(ApiConfigV2.telegramBotDeepLinkBase);
try {
final launched = await launchUrl(
deepLink,
mode: LaunchMode.externalApplication,
);
if (!launched) {
throw Exception('Could not launch Telegram');
}
} catch (e, s) {
log(
'Error opening Telegram bot',
error: e,
stackTrace: s,
name: 'SignInWithTelegram',
);
widget.onError(
'Не удалось открыть Telegram. Попробуйте вручную: ${deepLink.toString()}',
);
}
}
@override
Widget build(BuildContext context) {
@ -460,12 +458,29 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Введите код из Telegram бота',
'Два способа входа:',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 16),
// Вариант 1: Ввод кода вручную
Text(
'Вариант 1: Введите код вручную',
style: theme.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
Text(
'Код будет проверен автоматически при длине более 4 символов',
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w500,
color: theme.colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 12),
TextField(
controller: _telegramCodeController,
@ -500,60 +515,28 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
maxLength: 6,
onSubmitted: (_) => _loginWithTelegram(),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: widget.isLoading ? null : _generateTelegramCode,
icon: const Icon(Icons.bolt, size: 20),
label: Text(
widget.isLoading ? 'Создание...' : 'Получить код',
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w700,
),
),
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
onPressed: widget.isLoading ? null : _openTelegramBot,
icon: const Icon(Icons.telegram, size: 20),
label: Text(
'Открыть бота',
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w700,
),
),
style: OutlinedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: BorderSide(color: theme.dividerColor, width: 1),
),
),
),
],
),
if (_webCodeStatus != null) ...[
const SizedBox(height: 16),
_buildTelegramStatusCard(),
],
const SizedBox(height: 24),
// Вариант 2: Кнопка входа
Text(
'Вариант 2: Нажмите кнопку для автоматической генерации кода',
style: theme.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w700,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton.icon(
onPressed: widget.isLoading ? null : _loginWithTelegram,
onPressed: widget.isLoading ? null : _generateTelegramCode,
icon: const Icon(Icons.telegram, size: 24),
label: Text(
'Войти с кодом Telegram',
'Войти через телеграм',
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w700,
),