import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/auth/auth_controller.dart'; import '../../core/config.dart'; import '../settings/api_base_url_dialog.dart'; class LoginPage extends ConsumerStatefulWidget { const LoginPage({super.key}); @override ConsumerState createState() => _LoginPageState(); } class _LoginPageState extends ConsumerState { final _email = TextEditingController(); final _password = TextEditingController(); String? _error; bool _busy = false; @override void dispose() { _email.dispose(); _password.dispose(); super.dispose(); } Future _submit() async { setState(() { _busy = true; _error = null; }); final error = await ref .read(authControllerProvider.notifier) .login(_email.text.trim(), _password.text); if (!mounted) return; setState(() { _busy = false; _error = error; }); } @override Widget build(BuildContext context) { final status = ref.watch(authControllerProvider).status; return Scaffold( body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 360), child: Padding( padding: const EdgeInsets.all(24), child: status == AuthStatus.unknown ? const CircularProgressIndicator() : AutofillGroup( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'fin-tracker', style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Flexible( child: Text( ref.watch(apiBaseUrlProvider), style: Theme.of(context).textTheme.bodySmall, overflow: TextOverflow.ellipsis, ), ), IconButton( icon: const Icon(Icons.edit_outlined, size: 16), tooltip: 'Изменить адрес', onPressed: () => showApiBaseUrlDialog(context), ), ], ), const SizedBox(height: 24), TextField( controller: _email, autofillHints: const [AutofillHints.username], keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(labelText: 'Email'), ), const SizedBox(height: 12), TextField( controller: _password, autofillHints: const [AutofillHints.password], obscureText: true, onSubmitted: (_) => _busy ? null : _submit(), decoration: const InputDecoration( labelText: 'Пароль', ), ), if (_error != null) ...[ const SizedBox(height: 12), Text( _error!, style: TextStyle( color: Theme.of(context).colorScheme.error, ), ), ], const SizedBox(height: 24), FilledButton( onPressed: _busy ? null : _submit, child: _busy ? const SizedBox.square( dimension: 18, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text('Войти'), ), ], ), ), ), ), ), ); } }