import 'package:flutter/material.dart'; import 'package:moonwell_launcher/app/launcher_version.dart'; import 'package:moonwell_launcher/app/design_system/mw_shells.dart'; import 'package:moonwell_launcher/app/theme/moonwell_design_system.dart'; enum MwAuthenticationMode { login, registration } class MwAuthenticationForm extends StatefulWidget { const MwAuthenticationForm({ super.key, required this.usernameController, required this.passwordController, required this.onSubmit, this.emailController, this.passwordConfirmationController, this.inviteCodeController, this.mode = MwAuthenticationMode.login, this.onModeChanged, this.termsAccepted = false, this.onTermsChanged, this.loading = false, this.error, this.success, }); final TextEditingController usernameController; final TextEditingController passwordController; final TextEditingController? emailController; final TextEditingController? passwordConfirmationController; final TextEditingController? inviteCodeController; final VoidCallback onSubmit; final MwAuthenticationMode mode; final ValueChanged? onModeChanged; final bool termsAccepted; final ValueChanged? onTermsChanged; final bool loading; final String? error; final String? success; @override State createState() => _MwAuthenticationFormState(); } class _MwAuthenticationFormState extends State { bool _remember = true; @override Widget build(BuildContext context) { final accent = MoonWellDesignTokens.of(context).accent; final registering = widget.mode == MwAuthenticationMode.registration; final launcherVersion = LauncherVersionScope.of(context); return AutofillGroup( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const MwBrandMark(width: 210, compact: true), const SizedBox(height: 28), Text( registering ? 'РЕГИСТРАЦИЯ' : 'ВХОД', style: TextStyle(color: accent, fontSize: 10, letterSpacing: 2.4), ), const SizedBox(height: 10), Text( registering ? 'Создать аккаунт' : 'С возвращением', style: const TextStyle( fontFamily: 'Cinzel', color: Color(0xFFECE4D0), fontSize: 30, letterSpacing: 1, ), ), const SizedBox(height: 7), Text( registering ? 'Зарегистрируй игровой аккаунт MoonWell.' : 'Войди в свой аккаунт, чтобы продолжить путь.', style: const TextStyle( fontFamily: 'Cormorant Garamond', fontStyle: FontStyle.italic, color: Color(0x80ECE4D0), fontSize: 15, ), ), const SizedBox(height: 22), Row( children: [ _Tab( label: 'ВХОД', selected: !registering, accent: accent, onTap: widget.loading ? null : () => widget.onModeChanged?.call( MwAuthenticationMode.login, ), ), _Tab( label: 'РЕГИСТРАЦИЯ', selected: registering, accent: accent, onTap: widget.loading ? null : () => widget.onModeChanged?.call( MwAuthenticationMode.registration, ), ), ], ), const SizedBox(height: 18), _FieldLabel(text: registering ? 'ЛОГИН' : 'ЛОГИН ИЛИ EMAIL'), const SizedBox(height: 7), TextField( controller: widget.usernameController, enabled: !widget.loading, textInputAction: TextInputAction.next, autofillHints: const [AutofillHints.username], decoration: const InputDecoration(hintText: 'Aranthel'), ), if (registering) ...[ const SizedBox(height: 14), const _FieldLabel(text: 'EMAIL'), const SizedBox(height: 7), TextField( controller: widget.emailController, enabled: !widget.loading, keyboardType: TextInputType.emailAddress, textInputAction: TextInputAction.next, autofillHints: const [AutofillHints.email], decoration: const InputDecoration(hintText: 'player@example.com'), ), ], const SizedBox(height: 14), _FieldLabel(text: 'ПАРОЛЬ'), const SizedBox(height: 7), TextField( controller: widget.passwordController, enabled: !widget.loading, obscureText: true, textInputAction: registering ? TextInputAction.next : TextInputAction.done, autofillHints: [ registering ? AutofillHints.newPassword : AutofillHints.password, ], onSubmitted: registering ? null : (_) => widget.onSubmit(), ), if (registering) ...[ const SizedBox(height: 14), const _FieldLabel(text: 'ПОВТОРИТЕ ПАРОЛЬ'), const SizedBox(height: 7), TextField( controller: widget.passwordConfirmationController, enabled: !widget.loading, obscureText: true, textInputAction: TextInputAction.next, autofillHints: const [AutofillHints.newPassword], ), const SizedBox(height: 14), const _FieldLabel(text: 'ИНВАЙТ-КОД (НЕОБЯЗАТЕЛЬНО)'), const SizedBox(height: 7), TextField( controller: widget.inviteCodeController, enabled: !widget.loading, textInputAction: TextInputAction.done, onSubmitted: (_) => widget.onSubmit(), ), ], if (widget.error != null) ...[ const SizedBox(height: 10), Text( widget.error!, style: const TextStyle(color: Color(0xFFD76A78), fontSize: 12), ), ], if (widget.success != null) ...[ const SizedBox(height: 10), Text( widget.success!, style: const TextStyle(color: Color(0xFF6FC28A), fontSize: 12), ), ], const SizedBox(height: 8), if (registering) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 24, child: Checkbox( value: widget.termsAccepted, onChanged: widget.loading ? null : (value) => widget.onTermsChanged?.call(value ?? false), ), ), const SizedBox(width: 8), const Expanded( child: Text( 'Я принимаю правила сервера и пользовательское соглашение', style: TextStyle(color: Color(0x9AECE4D0), fontSize: 11), ), ), ], ) else Row( children: [ SizedBox( width: 24, child: Checkbox( value: _remember, onChanged: widget.loading ? null : (value) => setState(() => _remember = value ?? false), ), ), const SizedBox(width: 8), const Text( 'Запомнить меня', style: TextStyle(color: Color(0x9AECE4D0), fontSize: 11), ), const Spacer(), Text( 'Забыли пароль?', style: TextStyle(color: accent, fontSize: 11), ), ], ), const SizedBox(height: 18), SizedBox( height: 54, child: ElevatedButton( onPressed: widget.loading ? null : widget.onSubmit, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6D499E), foregroundColor: const Color(0xFFECE4D0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), child: widget.loading ? const SizedBox.square( dimension: 18, child: CircularProgressIndicator(strokeWidth: 2), ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( registering ? 'СОЗДАТЬ АККАУНТ' : 'ВОЙТИ', style: const TextStyle( fontFamily: 'Cinzel', letterSpacing: 2.5, ), ), const SizedBox(width: 14), const Icon(Icons.arrow_forward, size: 18), ], ), ), ), const SizedBox(height: 28), Center( child: Text( 'MOONWELL · V $launcherVersion · PLAY.MOON-WELL.ONLINE', style: const TextStyle( fontFamily: 'JetBrains Mono', color: Color(0x52ECE4D0), fontSize: 8, letterSpacing: 1.2, ), ), ), ], ), ); } } class _FieldLabel extends StatelessWidget { const _FieldLabel({required this.text}); final String text; @override Widget build(BuildContext context) => Text( text, style: const TextStyle( fontFamily: 'JetBrains Mono', color: Color(0x80ECE4D0), fontSize: 9, letterSpacing: 1.5, ), ); } class _Tab extends StatelessWidget { const _Tab({ required this.label, required this.accent, this.onTap, this.selected = false, }); final String label; final Color accent; final VoidCallback? onTap; final bool selected; @override Widget build(BuildContext context) => Expanded( child: InkWell( onTap: onTap, child: Container( height: 38, alignment: Alignment.center, decoration: BoxDecoration( border: Border( bottom: BorderSide(color: selected ? accent : Colors.transparent), ), ), child: Text( label, style: TextStyle( fontFamily: 'Cinzel', color: selected ? const Color(0xFFECE4D0) : const Color(0x80ECE4D0), fontSize: 9, letterSpacing: 1.5, ), ), ), ), ); }