Chepuhagram/lib/presentation/screens/account_setup_screen.dart

288 lines
10 KiB
Dart

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 _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();
}
@override
Widget build(BuildContext context) {
final authProvider = context.watch<AuthProvider>();
final themeProv = context.watch<ThemeProvider>();
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
body: Stack(
children: [
// Background Wallpaper
if (themeProv.wallpaperPath != null)
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(File(themeProv.wallpaperPath!)),
fit: BoxFit.cover,
),
),
),
// Blur Overlay
if (themeProv.wallpaperPath != null)
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
child: Container(
color: Colors.black.withOpacity(0.1),
),
),
Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
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: 48),
// Поле Имя
_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: 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: 40),
// Кнопка Продолжить
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,
}) {
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,
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,
);
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();
_passwordController.dispose();
_confirmPasswordController.dispose();
_animationController.dispose();
super.dispose();
}
}