import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:inventory_app/models/depot.dart'; import 'package:inventory_app/my_app.dart'; import 'package:inventory_app/service/axelor_client.dart'; import 'package:lottie/lottie.dart'; import 'package:quickalert/quickalert.dart'; import 'package:inventory_app/home.dart'; import '../constants.dart'; import '../controllers/simple_ui_controller.dart'; import 'package:inventory_app/controllers/theme_controller.dart'; class LoginView extends StatefulWidget { const LoginView({super.key}); @override State createState() => _LoginViewState(); } class _LoginViewState extends State { TextEditingController nameController = TextEditingController(text: ""); TextEditingController passwordController = TextEditingController(text: ""); final _formKey = GlobalKey(); bool _loading = false; late AxelorClient client; bool _clientInitialized = false; SimpleUIController simpleUIController = Get.put(SimpleUIController()); @override void initState() { super.initState(); _initClient(); } Future _initClient() async { client = await AxelorClient.create(); setState(() => _clientInitialized = true); } @override Widget build(BuildContext context) { final themeController = Get.find(); final isDark = themeController.isDarkMode.value; final size = MediaQuery.of(context).size; return Scaffold( resizeToAvoidBottomInset: true, body: Stack( children: [ const _FancyBackground(), // 🧊 Adaptive gradient background Center( child: SingleChildScrollView( padding: const EdgeInsets.all(20), child: _GlassCard( child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // 🌊 Animated wave header Lottie.asset( 'assets/wave.json', height: size.height * 0.25, repeat: true, ), const SizedBox(height: 20), Text( "Se connecter", style: kLoginTitleStyle(size * 0.80).copyWith( color: isDark ? Colors.white.withOpacity(0.95) : Colors.blue.shade700, ), ), const SizedBox(height: 8), Text( "Bienvenue", style: kLoginSubtitleStyle(size).copyWith( color: isDark ? Colors.white : Colors.black.withOpacity(0.7), ), ), const SizedBox(height: 28), // 👤 Username TextFormField( controller: nameController, style: kTextFormFieldStyle( color: isDark ? Colors.white.withOpacity(0.9) : Colors.black87, ), decoration: _inputDecoration( hint: 'Nom d\'utilisateur', icon: Icons.person, isDark: isDark, ), validator: (value) { if (value == null || value.isEmpty) { return 'Entrer un nom d\'utilisateur'; } else if (value.length < 4) { return 'Au moins 4 caractères'; } else if (value.length > 20) { return 'Maximum 20 caractères'; } return null; }, ), const SizedBox(height: 16), // 🔒 Password Obx( () => TextFormField( controller: passwordController, obscureText: simpleUIController.isObscure.value, style: kTextFormFieldStyle( color: isDark ? Colors.white.withOpacity(0.9) : Colors.black87, ), decoration: _inputDecoration( hint: 'Mot de passe', icon: Icons.lock_open_rounded, isDark: isDark, suffix: IconButton( icon: Icon( simpleUIController.isObscure.value ? Icons.visibility : Icons.visibility_off, color: isDark ? Colors.white70 : Colors.black54, ), onPressed: simpleUIController.isObscureActive, ), ), validator: (value) { if (value == null || value.isEmpty) { return 'Entrer un mot de passe'; } else if (value.length < 6) { return 'Au moins 6 caractères'; } return null; }, ), ), const SizedBox(height: 14), Text( "Contactez votre administrateur si vous avez oublié votre mot de passe", style: kLoginTermsAndPrivacyStyle(size).copyWith( color: isDark ? Colors.white54 : Colors.black.withOpacity(0.5), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), // 🚪 Login button SizedBox( width: double.infinity, height: 55, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isDark ? Colors.blue.shade400 : Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), shadowColor: Colors.blue.withOpacity(0.4), elevation: 8, ), onPressed: _loading ? null : () async { if (_formKey.currentState!.validate()) { setState(() => _loading = true); if (!_clientInitialized) { QuickAlert.show( context: context, type: QuickAlertType.error, title: 'Erreur', text: 'Client non initialisé. Veuillez réessayer.', ); setState(() => _loading = false); return; } final loggedIn = await client.login( nameController.text.trim(), passwordController.text.trim(), ); if (loggedIn) { // final locations = // await client.fetchLocations(); Get.off( () => const MyApp(), // arguments: locations, ); } else { QuickAlert.show( context: context, type: QuickAlertType.error, title: 'Erreur', text: 'Nom d\'utilisateur ou mot de passe incorrect', ); } setState(() => _loading = false); } }, child: _loading ? const Center( child: CircularProgressIndicator( color: Colors.white, ), ) : const Text( 'Se connecter', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w600, ), ), ), ), const SizedBox(height: 16), // 🌗 Toggle theme Obx(() { final isDark = themeController.isDarkMode.value; return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( isDark ? Icons.dark_mode_rounded : Icons.light_mode_rounded, color: isDark ? Colors.white70 : Colors.blue.shade700, ), Switch( value: isDark, onChanged: (v) { themeController.toggleTheme(); setState(() {}); }, activeColor: Colors.blue, ), Text( isDark ? 'Mode sombre' : 'Mode clair', style: kTextFormFieldStyle( color: isDark ? Colors.white70 : Colors.black87, ), ), ], ); }), ], ), ), ), ), ), ], ), ); } InputDecoration _inputDecoration({ required String hint, required IconData icon, bool isDark = false, Widget? suffix, }) { return InputDecoration( prefixIcon: Icon(icon, color: isDark ? Colors.white70 : Colors.black54), suffixIcon: suffix, hintText: hint, hintStyle: TextStyle(color: isDark ? Colors.white54 : Colors.black45), filled: true, fillColor: isDark ? Colors.white.withOpacity(0.08) : Colors.white.withOpacity(0.7), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: BorderSide.none, ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), ); } } /// Glass card reused class _GlassCard extends StatelessWidget { final Widget child; const _GlassCard({required this.child}); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient( colors: isDark ? [ Colors.white.withOpacity(0.06), Colors.white.withOpacity(0.03), ] : [ Colors.white.withOpacity(0.4), Colors.white.withOpacity(0.2), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), border: Border.all( color: isDark ? Colors.white.withOpacity(0.08) : Colors.white.withOpacity(0.5), ), boxShadow: [ BoxShadow( color: isDark ? Colors.black.withOpacity(0.4) : Colors.blueGrey.withOpacity(0.15), blurRadius: 18, offset: const Offset(0, 10), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), child: Padding(padding: const EdgeInsets.all(20), child: child), ), ), ); } } /// Gradient background reused class _FancyBackground extends StatelessWidget { const _FancyBackground(); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDark ? [ const Color(0xFF0A0A0A), const Color(0xFF121212), const Color(0xFF1E1E1E), ] : [ const Color(0xFFEEF2FF), const Color(0xFFE0F2FE), const Color(0xFFE6FFFA), ], ), ), child: Stack( children: [ Positioned( top: -60, right: -30, child: _Blob( color: isDark ? Colors.blue.withOpacity(0.1) : Colors.blue.withOpacity(0.18), size: 180, ), ), Positioned( bottom: -40, left: -30, child: _Blob( color: isDark ? Colors.cyanAccent.withOpacity(0.08) : Colors.cyan.withOpacity(0.16), size: 160, ), ), ], ), ); } } class _Blob extends StatelessWidget { final Color color; final double size; const _Blob({required this.color, required this.size}); @override Widget build(BuildContext context) { return Container( width: size, height: size, decoration: BoxDecoration( color: color, shape: BoxShape.circle, boxShadow: [BoxShadow(color: color, blurRadius: 60, spreadRadius: 30)], ), ); } }