import 'package:flutter/material.dart'; import 'package:notas/data/api_client.dart'; import 'package:notas/theme/app_palette.dart'; class VaultAccessScreen extends StatefulWidget { const VaultAccessScreen({ super.key, required this.isBusy, required this.onCreateAccountPressed, required this.onSignInPressed, required this.onContinueWithoutAccount, }); final bool isBusy; final Future Function(String email, String password) onCreateAccountPressed; final Future Function(String email, String password) onSignInPressed; final Future Function() onContinueWithoutAccount; @override State createState() => _VaultAccessScreenState(); } class _VaultAccessScreenState extends State { final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); final TextEditingController _endpointController = TextEditingController(); bool _endpointLoading = true; @override void initState() { super.initState(); _loadEndpoint(); } Future _loadEndpoint() async { final String endpoint = await ApiConfig.getEndpoint(); if (!mounted) return; _endpointController.text = endpoint; setState(() { _endpointLoading = false; }); } Future _persistEndpointFromField() async { final String value = _endpointController.text.trim(); if (value.isEmpty) return; await ApiConfig.setEndpoint(value); } @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } Future _handleCreateAccount() async { await _persistEndpointFromField(); await widget.onCreateAccountPressed( _emailController.text.trim(), _passwordController.text, ); } Future _handleSignIn() async { await _persistEndpointFromField(); await widget.onSignInPressed( _emailController.text.trim(), _passwordController.text, ); } @override Widget build(BuildContext context) { final AppPalette palette = Theme.of(context).extension()!; return Scaffold( body: Container( decoration: BoxDecoration(gradient: palette.backdropGradient), child: SafeArea( child: Column( children: [ Expanded( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 460), child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: palette.cardBackground, borderRadius: BorderRadius.circular(24), border: Border.all(color: palette.border), boxShadow: [ BoxShadow( color: palette.shadowSoft, blurRadius: 30, offset: const Offset(0, 18), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Icon( Icons.lock_outline, color: Colors.white, size: 44, ), const SizedBox(height: 16), const Text( 'Mis Notas', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 30, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 10), Text( 'Tus notas se guardan cifradas en este dispositivo. La cuenta y la sincronización vendrán después.', textAlign: TextAlign.center, style: TextStyle( color: palette.textSecondary, height: 1.4, ), ), const SizedBox(height: 28), _endpointLoading ? const SizedBox( height: 48, child: Center( child: CircularProgressIndicator(), ), ) : TextField( controller: _endpointController, enabled: !widget.isBusy, keyboardType: TextInputType.url, style: const TextStyle(color: Colors.white), decoration: InputDecoration( labelText: 'API endpoint', labelStyle: TextStyle( color: palette.textSecondary, ), filled: true, fillColor: palette.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide( color: palette.border, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide( color: palette.border, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide( color: palette.accent, width: 1.2, ), ), ), ), const SizedBox(height: 16), TextField( controller: _emailController, enabled: !widget.isBusy, keyboardType: TextInputType.text, style: const TextStyle(color: Colors.white), decoration: InputDecoration( labelText: 'Usuario', labelStyle: TextStyle( color: palette.textSecondary, ), filled: true, fillColor: palette.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide(color: palette.border), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide(color: palette.border), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide( color: palette.accent, width: 1.2, ), ), ), ), const SizedBox(height: 16), TextField( controller: _passwordController, enabled: !widget.isBusy, obscureText: true, style: const TextStyle(color: Colors.white), decoration: InputDecoration( labelText: 'Contraseña', labelStyle: TextStyle( color: palette.textSecondary, ), filled: true, fillColor: palette.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide(color: palette.border), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide(color: palette.border), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide( color: palette.accent, width: 1.2, ), ), ), ), const SizedBox(height: 22), FilledButton( onPressed: widget.isBusy ? null : _handleCreateAccount, style: FilledButton.styleFrom( padding: const EdgeInsets.symmetric( vertical: 14, ), ), child: widget.isBusy ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text('Crear cuenta'), ), const SizedBox(height: 10), OutlinedButton( onPressed: widget.isBusy ? null : _handleSignIn, style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric( vertical: 14, ), side: BorderSide(color: palette.border), foregroundColor: palette.textPrimary, ), child: const Text('Iniciar sesión'), ), const SizedBox(height: 18), TextButton( onPressed: widget.isBusy ? null : widget.onContinueWithoutAccount, child: const Text('Entrar sin cuenta'), ), ], ), ), ), ), ), ), ], ), ), ), ); } }