import '../../../l10n/app_localizations.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/auth/screens/mpin_screen.dart'; import 'package:kmobile/security/secure_storage.dart'; import '../../../app.dart'; import '../controllers/auth_cubit.dart'; import '../controllers/auth_state.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override LoginScreenState createState() => LoginScreenState(); } class LoginScreenState extends State with SingleTickerProviderStateMixin { final _formKey = GlobalKey(); final _customerNumberController = TextEditingController(); final _passwordController = TextEditingController(); bool _obscurePassword = true; //bool _showWelcome = true; late AnimationController _logoController; late Animation _logoAnimation; @override void initState() { super.initState(); _logoController = AnimationController( vsync: this, duration: const Duration(seconds: 1), )..repeat(reverse: true); _logoAnimation = Tween(begin: 0.2, end: 1).animate(_logoController); } @override void dispose() { _logoController.dispose(); _customerNumberController.dispose(); _passwordController.dispose(); super.dispose(); } void _submitForm() { if (_formKey.currentState!.validate()) { context.read().login( _customerNumberController.text.trim(), _passwordController.text, ); } } @override Widget build(BuildContext context) { return Scaffold( // appBar: AppBar(title: const Text('Login')), body: BlocConsumer( listener: (context, state) async { if (state is Authenticated) { final storage = getIt(); final mpin = await storage.read('mpin'); if (mpin == null) { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => MPinScreen( mode: MPinMode.set, onCompleted: (_) { Navigator.of( context, rootNavigator: true, ).pushReplacement( MaterialPageRoute( builder: (_) => const NavigationScaffold(), ), ); }, ), ), ); } else { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const NavigationScaffold()), ); } } else if (state is AuthError) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(state.message))); } }, builder: (context, state) { return Padding( padding: const EdgeInsets.all(24.0), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 🔁 Animated Blinking Logo FadeTransition( opacity: _logoAnimation, child: Image.asset( 'assets/images/logo.png', width: 150, height: 150, errorBuilder: (context, error, stackTrace) { return Icon( Icons.account_balance, size: 100, color: Theme.of(context).primaryColor, ); }, ), ), const SizedBox(height: 16), // Title Text( AppLocalizations.of(context).kccb, style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor, ), ), const SizedBox(height: 48), TextFormField( controller: _customerNumberController, decoration: InputDecoration( labelText: AppLocalizations.of(context).customerNumber, // prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), isDense: true, filled: true, fillColor: Theme.of(context).scaffoldBackgroundColor, enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.black), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.black, width: 2), ), ), keyboardType: TextInputType.number, textInputAction: TextInputAction.next, validator: (value) { if (value == null || value.isEmpty) { return AppLocalizations.of(context).pleaseEnterUsername; } return null; }, ), const SizedBox(height: 24), // Password TextFormField( controller: _passwordController, obscureText: _obscurePassword, textInputAction: TextInputAction.done, onFieldSubmitted: (_) => _submitForm(), // ⌨️ Enter key submits decoration: InputDecoration( labelText: AppLocalizations.of(context).password, border: const OutlineInputBorder(), isDense: true, filled: true, fillColor: Theme.of(context).scaffoldBackgroundColor, enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.black), ), focusedBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.black, width: 2), ), suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), ), validator: (value) { if (value == null || value.isEmpty) { return AppLocalizations.of(context).pleaseEnterPassword; } return null; }, ), const SizedBox(height: 24), //Login Button SizedBox( width: 250, child: ElevatedButton( onPressed: state is AuthLoading ? null : _submitForm, style: ElevatedButton.styleFrom( shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Theme.of(context).scaffoldBackgroundColor, foregroundColor: Theme.of(context).primaryColorDark, side: const BorderSide(color: Colors.black, width: 1), elevation: 0, ), child: state is AuthLoading ? const CircularProgressIndicator() : Text( AppLocalizations.of(context).login, style: TextStyle(fontSize: 16), ), ), ), const SizedBox(height: 15), Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Row( children: [ Expanded(child: Divider()), Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Text(AppLocalizations.of(context).or), ), Expanded(child: Divider()), ], ), ), const SizedBox(height: 25), // Register Button SizedBox( width: 250, child: ElevatedButton( //disable until registration is implemented onPressed: null, style: OutlinedButton.styleFrom( shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Theme.of(context).primaryColorLight, foregroundColor: Colors.black, ), child: Text(AppLocalizations.of(context).register), ), ), ], ), ), ); }, ), ); } } /*import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/auth/screens/mpin_screen.dart'; import 'package:kmobile/security/secure_storage.dart'; import '../../../app.dart'; import '../controllers/auth_cubit.dart'; import '../controllers/auth_state.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override LoginScreenState createState() => LoginScreenState(); } class LoginScreenState extends State { final _formKey = GlobalKey(); final _customerNumberController = TextEditingController(); final _passwordController = TextEditingController(); bool _obscurePassword = true; @override void dispose() { _customerNumberController.dispose(); _passwordController.dispose(); super.dispose(); } void _submitForm() { if (_formKey.currentState!.validate()) { context.read().login( _customerNumberController.text.trim(), _passwordController.text, ); } } @override Widget build(BuildContext context) { return Scaffold( // appBar: AppBar(title: const Text('Login')), body: BlocConsumer( listener: (context, state) async { if (state is Authenticated) { final storage = getIt(); final mpin = await storage.read('mpin'); if (mpin == null) { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => MPinScreen( mode: MPinMode.set, onCompleted: (_) { Navigator.of(context, rootNavigator: true) .pushReplacement( MaterialPageRoute( builder: (_) => const NavigationScaffold()), ); }, ), ), ); } else { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const NavigationScaffold()), ); } } else if (state is AuthError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.message)), ); } }, builder: (context, state) { return Padding( padding: const EdgeInsets.all(24.0), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset('assets/images/logo.png', width: 150, height: 150, errorBuilder: (context, error, stackTrace) { return const Icon(Icons.account_balance, size: 100, color: Colors.blue); }), const SizedBox(height: 16), // Title const Text( 'KCCB', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.blue), ), const SizedBox(height: 48), TextFormField( controller: _customerNumberController, decoration: const InputDecoration( labelText: 'Customer Number', // prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), isDense: true, filled: true, fillColor: Colors.white, enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.black), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.black, width: 2), ), ), keyboardType: TextInputType.number, textInputAction: TextInputAction.next, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your username'; } return null; }, ), const SizedBox(height: 24), TextFormField( controller: _passwordController, decoration: InputDecoration( labelText: 'Password', // prefixIcon: const Icon(Icons.lock), border: const OutlineInputBorder(), isDense: true, filled: true, fillColor: Colors.white, enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.black), ), focusedBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.black, width: 2), ), suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), ), textInputAction: TextInputAction.done, obscureText: _obscurePassword, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } return null; }, ), const SizedBox(height: 24), SizedBox( width: 250, child: ElevatedButton( onPressed: state is AuthLoading ? null : _submitForm, style: ElevatedButton.styleFrom( shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Colors.white, foregroundColor: Colors.blueAccent, side: const BorderSide(color: Colors.black, width: 1), elevation: 0), child: state is AuthLoading ? const CircularProgressIndicator() : const Text( 'Login', style: TextStyle(fontSize: 16), ), ), ), const SizedBox(height: 15), const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Row( children: [ Expanded(child: Divider()), Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Text('OR'), ), Expanded(child: Divider()), ], ), ), const SizedBox(height: 25), // Register Button SizedBox( width: 250, child: ElevatedButton( //disable until registration is implemented onPressed: null, style: OutlinedButton.styleFrom( shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Colors.lightBlue[100], foregroundColor: Colors.black), child: const Text('Register'), ), ), ], ), ), ); }, ), ); } } */