Implement local vault service with encryption key management and integrate it into the app. Add settings screen for data management and enhance home screen with new features. Update database connection for encryption support and modify repository to use the new database structure. Improve UI elements across the application for better user experience.

This commit is contained in:
2026-05-13 22:57:23 +02:00
parent 96f8f95924
commit 94fdfe51eb
16 changed files with 875 additions and 87 deletions
+206
View File
@@ -0,0 +1,206 @@
import 'package:flutter/material.dart';
import 'package:notas/widgets/app_title_bar.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<void> Function(String email, String password) onCreateAccountPressed;
final Future<void> Function(String email, String password) onSignInPressed;
final Future<void> Function() onContinueWithoutAccount;
@override
State<VaultAccessScreen> createState() => _VaultAccessScreenState();
}
class _VaultAccessScreenState extends State<VaultAccessScreen> {
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
Future<void> _handleCreateAccount() async {
await widget.onCreateAccountPressed(
_emailController.text.trim(),
_passwordController.text,
);
}
Future<void> _handleSignIn() async {
await widget.onSignInPressed(
_emailController.text.trim(),
_passwordController.text,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF191A1D),
Color(0xFF222326),
Color(0xFF101114),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: SafeArea(
child: Column(
children: [
const AppTitleBar(),
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: const Color(0xFF1D1E20),
borderRadius: BorderRadius.circular(24),
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.35),
blurRadius: 30,
offset: const Offset(0, 18),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Icon(
Icons.lock_outline,
color: Colors.amber,
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: Colors.white.withValues(alpha: 0.72),
height: 1.4,
),
),
const SizedBox(height: 28),
TextField(
controller: _emailController,
enabled: !widget.isBusy,
keyboardType: TextInputType.emailAddress,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: 'Email',
labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)),
filled: true,
fillColor: Colors.white.withValues(alpha: 0.05),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(color: Colors.amber, 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: Colors.white.withValues(alpha: 0.7)),
filled: true,
fillColor: Colors.white.withValues(alpha: 0.05),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(color: Colors.amber, 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: const BorderSide(color: Colors.white24),
foregroundColor: Colors.white,
),
child: const Text('Iniciar sesión'),
),
const SizedBox(height: 18),
TextButton(
onPressed: widget.isBusy ? null : widget.onContinueWithoutAccount,
child: const Text('Entrar sin cuenta'),
),
],
),
),
),
),
),
),
],
),
),
),
);
}
}