Chepuhagram/lib/presentation/screens/account_setup_screen.dart

329 lines
12 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:chepuhagram/logic/auth_provider.dart';
import 'package:chepuhagram/presentation/screens/contacts_screen.dart';
import 'package:chepuhagram/core/theme_manager.dart';
import 'dart:io';
class AccountSetupScreen extends StatefulWidget {
const AccountSetupScreen({super.key});
@override
State<AccountSetupScreen> createState() => _AccountSetupScreenState();
}
class _AccountSetupScreenState extends State<AccountSetupScreen>
with SingleTickerProviderStateMixin {
final _formKey = GlobalKey<FormState>();
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
final _phoneController = TextEditingController();
final _emailController = TextEditingController();
final _aboutController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController();
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 900),
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeIn),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.fastOutSlowIn,
),
);
_animationController.forward();
// Заполняем поля данными, если они уже есть на сервере
final auth = context.read<AuthProvider>();
_firstNameController.text = auth.firstName ?? '';
_lastNameController.text = auth.lastName ?? '';
_phoneController.text = auth.phone ?? '';
_emailController.text = auth.email ?? '';
_aboutController.text = auth.about ?? '';
}
@override
Widget build(BuildContext context) {
final authProvider = context.watch<AuthProvider>();
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
body: Stack(
children: [
Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SlideTransition(
position: _slideAnimation,
child: FadeTransition(
opacity: _fadeAnimation,
child: Column(
children: [
Icon(
Icons.person_add_alt_1_outlined,
size: 80,
color: colorScheme.primary,
),
const SizedBox(height: 16),
Text(
"Настройка аккаунта",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: colorScheme.primary,
),
),
const SizedBox(height: 12),
Text(
"Укажите ваши данные и создайте мастер-пароль",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: colorScheme.outline,
),
),
],
),
),
),
const SizedBox(height: 36),
// Поле Имя
_buildTextField(
controller: _firstNameController,
label: "Имя",
icon: Icons.person_outline,
validator: (value) =>
value!.isEmpty ? "Введите ваше имя" : null,
),
const SizedBox(height: 16),
// Поле Фамилия
_buildTextField(
controller: _lastNameController,
label: "Фамилия",
icon: Icons.person_outline,
),
const SizedBox(height: 16),
// Поле Телефон
_buildTextField(
controller: _phoneController,
label: "Телефон",
icon: Icons.phone_android_outlined,
keyboardType: TextInputType.phone,
),
const SizedBox(height: 16),
// Поле Почта
_buildTextField(
controller: _emailController,
label: "Электронная почта",
icon: Icons.mail_outline_rounded,
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 16),
// Поле О себе
_buildTextField(
controller: _aboutController,
label: "О себе",
icon: Icons.info_outline_rounded,
maxLines: 3,
),
const SizedBox(height: 24),
// Поле Мастер-пароль
_buildTextField(
controller: _passwordController,
label: "Мастер-пароль",
icon: Icons.lock_outline,
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Введите мастер-пароль';
}
if (value.length < 8) {
return 'Пароль должен быть не менее 8 символов';
}
return null;
},
),
const SizedBox(height: 16),
// Поле Подтверждение пароля
_buildTextField(
controller: _confirmPasswordController,
label: "Подтвердите пароль",
icon: Icons.lock_person_outlined,
obscureText: true,
validator: (value) {
if (value != _passwordController.text) {
return 'Пароли не совпадают';
}
return null;
},
),
const SizedBox(height: 32),
// Кнопка Продолжить
ElevatedButton(
onPressed: authProvider.isLoading ? null : _submit,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
),
child: authProvider.isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Text(
"Создать аккаунт",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
),
),
),
],
),
);
}
Widget _buildTextField({
required TextEditingController controller,
required String label,
required IconData icon,
String? Function(String?)? validator,
bool obscureText = false,
TextInputType? keyboardType,
int maxLines = 1,
}) {
final colorScheme = Theme.of(context).colorScheme;
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: Container(
decoration: BoxDecoration(
color: colorScheme.surfaceVariant.withOpacity(0.35),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: colorScheme.outlineVariant.withOpacity(0.15),
width: 1,
),
),
child: TextFormField(
controller: controller,
validator: validator,
obscureText: obscureText,
keyboardType: keyboardType,
maxLines: maxLines,
decoration: InputDecoration(
labelText: label,
labelStyle: TextStyle(color: colorScheme.outline),
prefixIcon: Icon(icon, color: colorScheme.outline),
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 18,
),
),
),
),
),
);
}
void _submit() async {
FocusScope.of(context).unfocus();
if (!_formKey.currentState!.validate()) return;
final authProvider = context.read<AuthProvider>();
try {
await authProvider.setupAccount(
_firstNameController.text.trim(),
_lastNameController.text.trim(),
_passwordController.text,
phone: _phoneController.text.trim(),
email: _emailController.text.trim(),
about: _aboutController.text.trim(),
);
if (mounted) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => const ContactsScreen()),
(route) => false,
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.toString().replaceAll('Exception: ', '')),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
}
}
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_phoneController.dispose();
_emailController.dispose();
_aboutController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
_animationController.dispose();
super.dispose();
}
}