475 lines
22 KiB
Dart
475 lines
22 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import '../theme.dart';
|
|
import 'otp_verification_screen.dart';
|
|
|
|
class MobileLoginScreen extends StatefulWidget {
|
|
const MobileLoginScreen({super.key});
|
|
|
|
@override
|
|
State<MobileLoginScreen> createState() => _MobileLoginScreenState();
|
|
}
|
|
|
|
class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|
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();
|
|
}
|
|
|
|
@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: [
|
|
// 1. Progress Bar: Step 2 of 5 with "Mobile Login" label on right
|
|
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),
|
|
|
|
// Title Header & Secure Badge Group
|
|
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),
|
|
|
|
// 6. Top Badge: Green "Secure OTP Verification" chip with lock icon
|
|
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),
|
|
|
|
// 2. Truecaller Card
|
|
Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFFF3F3F3), // light gray background (surface low)
|
|
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, // blue shield icon
|
|
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;
|
|
});
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('⚡ Phone verified automatically with Truecaller! Joining PozoApp...'),
|
|
backgroundColor: Color(0xFF005FAF),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => 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), // 8px for buttons
|
|
),
|
|
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),
|
|
|
|
// 3. Divider: "Or enter mobile number manually"
|
|
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),
|
|
|
|
// 4. Mobile Number field: Country code group on left, number field on right
|
|
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: [
|
|
// Flag and code prefix box
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
decoration: BoxDecoration(
|
|
border: Border(
|
|
right: BorderSide(color: theme.colorScheme.outlineVariant),
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
// Indian flag representation
|
|
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,
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
|
|
// Input field
|
|
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,
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
SizedBox(height: gap * 2),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// 5. Bottom buttons
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Full width red "Send OTP" button
|
|
ElevatedButton(
|
|
onPressed: _isValid
|
|
? () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => 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), // 8px default button radius
|
|
),
|
|
),
|
|
child: const Text('Send OTP'),
|
|
),
|
|
SizedBox(height: gap / 2),
|
|
// Outline style red "Help / Talk to Support" button with chat icon
|
|
OutlinedButton(
|
|
onPressed: () {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('💬 Connecting with Pozo Support... Please wait.'),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
},
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size.fromHeight(56),
|
|
side: const BorderSide(color: Color(0xFFAF101A), width: 2),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8), // 8px default button radius
|
|
),
|
|
),
|
|
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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|