import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:permission_handler/permission_handler.dart'; import 'package:contacts_service/contacts_service.dart'; import '../theme.dart'; import '../route_transitions.dart'; import 'otp_verification_screen.dart'; class MockContact { final String? displayName; final List phones; MockContact({this.displayName, required String phoneNumber}) : phones = [MockPhone(phoneNumber)]; } class MockPhone { final String? value; MockPhone(this.value); } class MobileLoginScreen extends StatefulWidget { const MobileLoginScreen({super.key}); @override State createState() => _MobileLoginScreenState(); } class _MobileLoginScreenState extends State { final TextEditingController _controller = TextEditingController(); bool _isValid = false; @override void initState() { super.initState(); _controller.addListener(_validateInput); } void _validateInput() { setState(() { _isValid = _controller.text.length == 10; }); } @override void dispose() { _controller.dispose(); super.dispose(); } Future _pickContact() async { const permission = Permission.contacts; var status = await permission.status; if (!mounted) return; if (status.isDenied) { final bool? proceed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Contacts Permission Required'), content: const Text( 'PozoApp requires access to your contacts to quickly auto-fill mobile numbers during registration/billing.', ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('Continue'), ), ], ), ); if (!mounted) return; if (proceed != true) return; status = await permission.request(); if (!mounted) return; } if (status.isGranted || kIsWeb) { _showContactPicker(); } else { showTopAlert( context, 'Contacts permission was denied. Please enter the number manually or enable it in Settings.', isError: true, ); } } Future> _loadContacts() async { if (kIsWeb) { await Future.delayed(const Duration(milliseconds: 600)); return [ MockContact(displayName: 'Amit Sharma', phoneNumber: '9876543210'), MockContact(displayName: 'Rajesh Patel', phoneNumber: '9823456789'), MockContact(displayName: 'Priya Sundaram', phoneNumber: '8765432109'), MockContact(displayName: 'Karan Malhotra', phoneNumber: '7654321098'), ]; } else { try { final List list = await ContactsService.getContacts(withThumbnails: false); return list; } catch (e) { return []; } } } void _selectContactNumber(String? rawNumber) { if (rawNumber == null) return; var digits = rawNumber.replaceAll(RegExp(r'\D'), ''); if (digits.length == 12 && digits.startsWith('91')) { digits = digits.substring(2); } if (digits.length == 11 && digits.startsWith('0')) { digits = digits.substring(1); } if (digits.length > 10) { digits = digits.substring(digits.length - 10); } setState(() { _controller.text = digits; _isValid = digits.length == 10; }); } Future _showContactPicker() async { List allContacts = []; List filteredContacts = []; bool isLoading = true; showDialog( context: context, builder: (context) { return StatefulBuilder( builder: (context, setDialogState) { if (isLoading) { _loadContacts().then((loaded) { setDialogState(() { allContacts = loaded; filteredContacts = loaded; isLoading = false; }); }); } return AlertDialog( title: const Text('Select Contact'), content: SizedBox( width: double.maxFinite, height: 400, child: Column( children: [ TextField( decoration: const InputDecoration( hintText: 'Search contacts...', prefixIcon: Icon(Icons.search), ), onChanged: (query) { setDialogState(() { filteredContacts = allContacts.where((contact) { final name = (contact.displayName ?? '').toLowerCase(); final phone = (contact.phones.isNotEmpty ? contact.phones.first.value ?? '' : '').toLowerCase(); return name.contains(query.toLowerCase()) || phone.contains(query.toLowerCase()); }).toList(); }); }, ), const SizedBox(height: 12), Expanded( child: isLoading ? const Center(child: CircularProgressIndicator()) : filteredContacts.isEmpty ? const Center(child: Text('No contacts found')) : ListView.builder( itemCount: filteredContacts.length, itemBuilder: (context, index) { final contact = filteredContacts[index]; final name = contact.displayName ?? 'Unknown'; final phone = contact.phones.isNotEmpty ? contact.phones.first.value : 'No number'; return ListTile( title: Text(name), subtitle: Text(phone), leading: CircleAvatar( backgroundColor: const Color(0xFFAF101A).withOpacity(0.1), child: Text( name.isNotEmpty ? name[0].toUpperCase() : '?', style: const TextStyle(color: Color(0xFFAF101A), fontWeight: FontWeight.bold), ), ), onTap: () { _selectContactNumber(phone); Navigator.pop(context); }, ); }, ), ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Close'), ) ], ); }, ); }, ); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final gap = context.responsiveGap; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back, color: Color(0xFFAF101A)), onPressed: () => Navigator.pop(context), ), title: Text( 'PozoApp', style: theme.textTheme.headlineMedium?.copyWith( color: const Color(0xFFAF101A), fontWeight: FontWeight.bold, ), ), centerTitle: false, elevation: 0, backgroundColor: Colors.transparent, ), body: SafeArea( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 600), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), Expanded( child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Step 2 of 5', style: theme.textTheme.labelMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.onSurfaceVariant, ), ), const Text( 'Mobile Login', style: TextStyle( fontFamily: 'Plus Jakarta Sans', fontSize: 14, fontWeight: FontWeight.bold, color: Color(0xFFAF101A), ), ), ], ), const SizedBox(height: 8), Row( children: List.generate(5, (index) { return Expanded( child: Container( height: 6, margin: EdgeInsets.only( left: index == 0 ? 0 : 3.0, right: index == 4 ? 0 : 3.0, ), decoration: BoxDecoration( color: index <= 1 ? const Color(0xFFAF101A) : const Color(0xFFE2E2E2), borderRadius: BorderRadius.circular(100), ), ), ); }), ), const SizedBox(height: 16), Text( 'Welcome Back', style: theme.textTheme.headlineLarge?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Text( 'Enter your mobile number to sign in or create a new account.', style: theme.textTheme.bodyMedium, ), const SizedBox(height: 16), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: const Color(0xFFFAFFD1).withOpacity(0.8), borderRadius: BorderRadius.circular(100), border: Border.all(color: const Color(0xFF016619).withOpacity(0.3)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.lock, size: 14, color: Color(0xFF016619)), const SizedBox(width: 6), Text( 'Secure OTP Verification', style: theme.textTheme.labelSmall?.copyWith( color: const Color(0xFF016619), fontWeight: FontWeight.bold, ), ), ], ), ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: const Color(0xFFF3F3F3), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFFE4BEBA).withOpacity(0.5)), ), child: Column( children: [ Row( children: [ Container( width: 40, height: 40, decoration: const BoxDecoration( color: Color(0xFF005FAF), shape: BoxShape.circle, ), child: const Icon( Icons.verified_user, color: Colors.white, size: 24, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Verify instantly with', style: theme.textTheme.bodySmall?.copyWith( color: Colors.grey[600], ), ), const Text( 'Truecaller', style: TextStyle( fontFamily: 'Plus Jakarta Sans', fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black, ), ), ], ), ), ], ), const SizedBox(height: 20), const Text( '+91 98765 43210', style: TextStyle( fontFamily: 'Plus Jakarta Sans', fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black, ), ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: () { _controller.text = '9876543210'; setState(() { _isValid = true; }); showTopAlert( context, 'Phone verified automatically with Truecaller! Joining PozoApp...', icon: Icons.verified_user_outlined, ); Navigator.push( context, FadeSlidePageRoute( child: const OtpVerificationScreen( mobileNumber: '9876543210', ), ), ); }, icon: const Icon(Icons.flash_on, size: 18, color: Colors.white), label: const Text( '1-Tap Verification', style: TextStyle( fontFamily: 'Inter', fontSize: 16, fontWeight: FontWeight.bold, ), ), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF005FAF), foregroundColor: Colors.white, minimumSize: const Size.fromHeight(56), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), elevation: 1, ), ), const SizedBox(height: 12), Text( 'No OTP required. Your phone will be verified automatically.', textAlign: TextAlign.center, style: theme.textTheme.bodySmall?.copyWith( color: Colors.grey[600], height: 1.4, ), ), ], ), ), SizedBox(height: gap), Row( children: [ const Expanded(child: Divider(color: Color(0xFFE4BEBA))), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( 'Or enter mobile number manually', style: theme.textTheme.labelMedium?.copyWith( color: Colors.grey[600], fontWeight: FontWeight.w500, fontSize: 12, ), ), ), const Expanded(child: Divider(color: Color(0xFFE4BEBA))), ], ), SizedBox(height: gap), Text( 'Mobile Number', style: theme.textTheme.labelSmall?.copyWith( color: theme.colorScheme.onSurface, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Container( height: 56, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: theme.colorScheme.outlineVariant), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.02), blurRadius: 4, offset: const Offset(0, 2), ) ], ), child: Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( border: Border( right: BorderSide(color: theme.colorScheme.outlineVariant), ), ), child: Row( children: [ Container( width: 22, height: 14, decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!, width: 0.5), ), child: Column( children: [ Container(height: 4, color: const Color(0xFFFF9933)), Container( height: 4, color: Colors.white, child: Center( child: Container( width: 2, height: 2, decoration: const BoxDecoration( color: Color(0xFF000080), shape: BoxShape.circle, ), ), ), ), Container(height: 4, color: const Color(0xFF128807)), ], ), ), const SizedBox(width: 8), Text( '+91', style: theme.textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.onSurface, ), ) ], ), ), Expanded( child: TextField( controller: _controller, keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], decoration: const InputDecoration( hintText: '00000 00000', border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, filled: false, contentPadding: EdgeInsets.symmetric(horizontal: 16), ), style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.onSurface, ), ), ), IconButton( icon: const Icon(Icons.contact_phone, color: Color(0xFFAF101A)), onPressed: _pickContact, ), ], ), ), SizedBox(height: gap * 2), ], ), ), ), Column( mainAxisSize: MainAxisSize.min, children: [ ElevatedButton( onPressed: _isValid ? () { Navigator.push( context, FadeSlidePageRoute( child: OtpVerificationScreen( mobileNumber: _controller.text, ), ), ); } : null, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(56), backgroundColor: _isValid ? const Color(0xFFAF101A) : Colors.grey[200], foregroundColor: _isValid ? Colors.white : Colors.grey[400], elevation: _isValid ? 2 : 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('Send OTP'), ), SizedBox(height: gap / 2), OutlinedButton( onPressed: () { showTopAlert( context, 'Connecting with Pozo Support... Please wait.', icon: Icons.support_agent_outlined, ); }, style: OutlinedButton.styleFrom( minimumSize: const Size.fromHeight(56), side: const BorderSide(color: Color(0xFFAF101A), width: 2), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.forum, color: Color(0xFFAF101A), size: 18), const SizedBox(width: 8), const Text( 'Help / Talk to Support', style: TextStyle( color: Color(0xFFAF101A), fontWeight: FontWeight.bold, fontSize: 16, ), ), ], ), ), ], ), ], ), ), ), ), ), ); } }