smart_advanced_text_field 2.0.0
smart_advanced_text_field: ^2.0.0 copied to clipboard
A professional, reusable Flutter TextField package with built-in validation, formatters, theming, OTP field, and 7 styles. Designed as a small UI framework for any Flutter project.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:smart_advanced_text_field/smart_advanced_text_field.dart';
void main() {
runApp(const SmartTextFieldExampleApp());
}
class SmartTextFieldExampleApp extends StatelessWidget {
const SmartTextFieldExampleApp({super.key});
@override
Widget build(BuildContext context) {
return SmartTextFieldThemeProvider(
theme: SmartTextFieldTheme.light(),
child: MaterialApp(
title: 'SmartTextField Examples',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const ExampleHomeScreen(),
),
);
}
}
// ── Home Screen ──────────────────────────────────────────────
class ExampleHomeScreen extends StatelessWidget {
const ExampleHomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade50,
appBar: AppBar(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
title: const Text(
'SmartTextField',
style: TextStyle(fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
_ExampleCard(
title: '1. Field Styles',
subtitle: 'All 7 visual styles',
icon: Icons.style,
color: Colors.indigo,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const FieldStylesScreen(),
),
),
),
_ExampleCard(
title: '2. Input Types',
subtitle: 'All 13 input types',
icon: Icons.keyboard,
color: Colors.blue,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const InputTypesScreen(),
),
),
),
_ExampleCard(
title: '3. Form Validation',
subtitle: 'Built-in validators',
icon: Icons.verified_user_outlined,
color: Colors.green,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const FormValidationScreen(),
),
),
),
_ExampleCard(
title: '4. OTP & PIN Field',
subtitle: 'Auto-focus jumping boxes',
icon: Icons.pin_outlined,
color: Colors.orange,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const OtpScreen(),
),
),
),
_ExampleCard(
title: '5. Named Constructors',
subtitle: '.email() .password() .search() .phone()',
icon: Icons.construction_outlined,
color: Colors.purple,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const NamedConstructorsScreen(),
),
),
),
_ExampleCard(
title: '6. Theme Support',
subtitle: 'Light, dark and custom themes',
icon: Icons.palette_outlined,
color: Colors.teal,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const ThemeScreen(),
),
),
),
_ExampleCard(
title: '7. Login Screen',
subtitle: 'Real world example',
icon: Icons.login_outlined,
color: Colors.red,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const LoginScreen(),
),
),
),
_ExampleCard(
title: '8. Register Screen',
subtitle: 'Real world example',
icon: Icons.person_add_outlined,
color: Colors.pink,
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const RegisterScreen(),
),
),
),
],
),
);
}
}
// ── Example Card ─────────────────────────────────────────────
class _ExampleCard extends StatelessWidget {
final String title;
final String subtitle;
final IconData icon;
final Color color;
final VoidCallback onTap;
const _ExampleCard({
required this.title,
required this.subtitle,
required this.icon,
required this.color,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Material(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
elevation: 2,
shadowColor: Colors.black12,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: color, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 2),
Text(
subtitle,
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade600,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Colors.grey.shade400,
),
],
),
),
),
),
);
}
}
// ── Shared Widgets ───────────────────────────────────────────
class _ScreenBase extends StatelessWidget {
final String title;
final List<Widget> children;
const _ScreenBase({
required this.title,
required this.children,
});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade50,
appBar: AppBar(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
title: Text(title),
centerTitle: true,
),
body: ListView(
padding: const EdgeInsets.all(20),
children: children,
),
);
}
}
class _Section extends StatelessWidget {
final String label;
final Widget child;
const _Section({required this.label, required this.child});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.grey.shade500,
letterSpacing: 0.5,
),
),
const SizedBox(height: 8),
child,
],
),
);
}
}
// ── Screen 1: Field Styles ───────────────────────────────────
class FieldStylesScreen extends StatelessWidget {
const FieldStylesScreen({super.key});
@override
Widget build(BuildContext context) {
return const _ScreenBase(
title: 'Field Styles',
children: [
_Section(
label: 'OUTLINED',
child: SmartTextField(
style: FieldStyle.outlined,
hintText: 'Outlined style',
labelText: 'Outlined',
prefixIcon: Icons.border_outer,
),
),
_Section(
label: 'FILLED',
child: SmartTextField(
style: FieldStyle.filled,
hintText: 'Filled style',
labelText: 'Filled',
prefixIcon: Icons.format_color_fill,
),
),
_Section(
label: 'UNDERLINED',
child: SmartTextField(
style: FieldStyle.underlined,
hintText: 'Underlined style',
labelText: 'Underlined',
prefixIcon: Icons.format_underline,
),
),
_Section(
label: 'ROUNDED',
child: SmartTextField(
style: FieldStyle.rounded,
hintText: 'Rounded style',
labelText: 'Rounded',
prefixIcon: Icons.radio_button_unchecked,
),
),
_Section(
label: 'SEARCH',
child: SmartTextField(
style: FieldStyle.search,
hintText: 'Search style...',
prefixIcon: Icons.search,
),
),
_Section(
label: 'MODERN',
child: SmartTextField(
style: FieldStyle.modern,
hintText: 'Modern style',
labelText: 'Modern',
prefixIcon: Icons.auto_awesome,
),
),
_Section(
label: 'FLAT',
child: SmartTextField(
style: FieldStyle.flat,
hintText: 'Flat style (no border)',
prefixIcon: Icons.crop_din,
),
),
],
);
}
}
// ── Screen 2: Input Types ────────────────────────────────────
class InputTypesScreen extends StatelessWidget {
const InputTypesScreen({super.key});
@override
Widget build(BuildContext context) {
return const _ScreenBase(
title: 'Input Types',
children: [
_Section(
label: 'EMAIL',
child: SmartTextField(
inputType: AppInputType.email,
hintText: 'Enter your email',
prefixIcon: Icons.email_outlined,
),
),
_Section(
label: 'PASSWORD',
child: SmartTextField(
inputType: AppInputType.password,
hintText: 'Enter password',
),
),
_Section(
label: 'PHONE',
child: SmartTextField(
inputType: AppInputType.phone,
hintText: '+92 300 1234567',
prefixIcon: Icons.phone_outlined,
),
),
_Section(
label: 'NUMBER',
child: SmartTextField(
inputType: AppInputType.number,
hintText: 'Enter a number',
prefixIcon: Icons.numbers,
),
),
_Section(
label: 'DECIMAL',
child: SmartTextField(
inputType: AppInputType.decimal,
hintText: '0.00',
prefixIcon: Icons.calculate_outlined,
),
),
_Section(
label: 'CURRENCY',
child: SmartTextField(
inputType: AppInputType.currency,
hintText: '0.00',
prefixText: 'PKR ',
prefixIcon: Icons.attach_money,
),
),
_Section(
label: 'URL',
child: SmartTextField(
inputType: AppInputType.url,
hintText: 'https://example.com',
prefixIcon: Icons.link,
),
),
_Section(
label: 'MULTILINE',
child: SmartTextField(
inputType: AppInputType.multiline,
hintText: 'Enter multiple lines of text...',
minLines: 3,
maxLines: 5,
),
),
_Section(
label: 'NAME',
child: SmartTextField(
inputType: AppInputType.name,
hintText: 'Enter your full name',
prefixIcon: Icons.person_outline,
),
),
_Section(
label: 'USERNAME',
child: SmartTextField(
inputType: AppInputType.username,
hintText: 'Enter username',
prefixIcon: Icons.alternate_email,
helperText: 'Letters, numbers and underscores only',
),
),
_Section(
label: 'READ ONLY',
child: SmartTextField(
readOnly: true,
initialValue: 'This field is read only',
prefixIcon: Icons.lock_outline,
),
),
_Section(
label: 'DISABLED',
child: SmartTextField(
enabled: false,
hintText: 'This field is disabled',
prefixIcon: Icons.block,
),
),
_Section(
label: 'WITH CHARACTER COUNTER',
child: SmartTextField(
hintText: 'Max 100 characters',
maxLength: 100,
showCounter: true,
prefixIcon: Icons.text_fields,
),
),
],
);
}
}
// ── Screen 3: Form Validation ────────────────────────────────
class FormValidationScreen extends StatefulWidget {
const FormValidationScreen({super.key});
@override
State<FormValidationScreen> createState() => _FormValidationScreenState();
}
class _FormValidationScreenState extends State<FormValidationScreen> {
final _formKey = GlobalKey<FormState>();
final _passwordController = TextEditingController();
String _status = '';
@override
void dispose() {
_passwordController.dispose();
super.dispose();
}
void _validate() {
setState(() {
_status = _formKey.currentState!.validate()
? '✅ All fields are valid!'
: '❌ Please fix the errors above';
});
}
void _reset() {
_formKey.currentState!.reset();
_passwordController.clear();
setState(() => _status = '');
}
@override
Widget build(BuildContext context) {
return _ScreenBase(
title: 'Form Validation',
children: [
Form(
key: _formKey,
child: Column(
children: [
_Section(
label: 'EMAIL',
child: SmartTextFormField.email(
validator: SmartValidators.email,
),
),
_Section(
label: 'PASSWORD',
child: SmartTextFormField.password(
controller: _passwordController,
validator: SmartValidators.password,
),
),
_Section(
label: 'CONFIRM PASSWORD',
child: SmartTextFormField(
inputType: AppInputType.password,
labelText: 'Confirm Password',
hintText: 'Re-enter your password',
validator: SmartValidators.confirmPassword(
_passwordController.text,
),
),
),
_Section(
label: 'PHONE',
child: SmartTextFormField.phone(
validator: SmartValidators.phone,
),
),
_Section(
label: 'USERNAME',
child: SmartTextFormField(
inputType: AppInputType.username,
labelText: 'Username',
hintText: 'Enter username',
prefixIcon: Icons.alternate_email,
validator: SmartValidators.username,
),
),
_Section(
label: 'NAME',
child: SmartTextFormField(
inputType: AppInputType.name,
labelText: 'Full Name',
hintText: 'Enter your full name',
prefixIcon: Icons.person_outline,
validator: SmartValidators.name,
),
),
_Section(
label: 'URL',
child: SmartTextFormField(
inputType: AppInputType.url,
labelText: 'Website',
hintText: 'https://example.com',
prefixIcon: Icons.link,
validator: SmartValidators.url,
),
),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _validate,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
padding:
const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text('Validate'),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton(
onPressed: _reset,
style: OutlinedButton.styleFrom(
padding:
const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text('Reset'),
),
),
],
),
if (_status.isNotEmpty) ...[
const SizedBox(height: 16),
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _status.contains('✅')
? Colors.green.shade50
: Colors.red.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: _status.contains('✅')
? Colors.green
: Colors.red,
),
),
child: Text(
_status,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: _status.contains('✅')
? Colors.green.shade700
: Colors.red.shade700,
),
textAlign: TextAlign.center,
),
),
],
],
),
),
],
);
}
}
// ── Screen 4: OTP ────────────────────────────────────────────
class OtpScreen extends StatefulWidget {
const OtpScreen({super.key});
@override
State<OtpScreen> createState() => _OtpScreenState();
}
class _OtpScreenState extends State<OtpScreen> {
String _otp6 = '';
String _pin4 = '';
@override
Widget build(BuildContext context) {
return _ScreenBase(
title: 'OTP & PIN Field',
children: [
_Section(
label: '6-DIGIT OTP',
child: Column(
children: [
SmartOtpField(
length: 6,
onCompleted: (otp) => setState(() => _otp6 = otp),
onChanged: (otp) => setState(() => _otp6 = otp),
),
if (_otp6.isNotEmpty) ...[
const SizedBox(height: 12),
Text(
'OTP: $_otp6',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
],
],
),
),
_Section(
label: '4-DIGIT PIN (OBSCURED)',
child: Column(
children: [
SmartOtpField(
length: 4,
obscureText: true,
boxWidth: 64,
boxHeight: 72,
borderRadius: 16,
onCompleted: (pin) => setState(() => _pin4 = pin),
onChanged: (pin) => setState(() => _pin4 = pin),
),
if (_pin4.length == 4) ...[
const SizedBox(height: 12),
const Text(
'✅ PIN entered',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
],
),
),
],
);
}
}
// ── Screen 5: Named Constructors ─────────────────────────────
class NamedConstructorsScreen extends StatelessWidget {
const NamedConstructorsScreen({super.key});
@override
Widget build(BuildContext context) {
return _ScreenBase(
title: 'Named Constructors',
children: [
_Section(
label: 'SmartTextField.email()',
child: SmartTextField.email(
onChanged: (_) {},
),
),
_Section(
label: 'SmartTextField.password()',
child: SmartTextField.password(
onChanged: (_) {},
),
),
_Section(
label: 'SmartTextField.search()',
child: SmartTextField.search(
onChanged: (_) {},
),
),
_Section(
label: 'SmartTextField.phone()',
child: SmartTextField.phone(
onChanged: (_) {},
),
),
_Section(
label: 'SmartTextFormField.email()',
child: SmartTextFormField.email(
validator: SmartValidators.email,
),
),
_Section(
label: 'SmartTextFormField.password()',
child: SmartTextFormField.password(
validator: SmartValidators.password,
),
),
_Section(
label: 'SmartTextFormField.phone()',
child: SmartTextFormField.phone(
validator: SmartValidators.phone,
),
),
],
);
}
}
// ── Screen 6: Theme Support ──────────────────────────────────
class ThemeScreen extends StatefulWidget {
const ThemeScreen({super.key});
@override
State<ThemeScreen> createState() => _ThemeScreenState();
}
class _ThemeScreenState extends State<ThemeScreen> {
bool _isDark = false;
@override
Widget build(BuildContext context) {
final theme = _isDark
? SmartTextFieldTheme.dark()
: SmartTextFieldTheme.light();
return SmartTextFieldThemeProvider(
theme: theme,
child: Scaffold(
backgroundColor: _isDark ? Colors.grey.shade900 : Colors.grey.shade50,
appBar: AppBar(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
title: const Text('Theme Support'),
centerTitle: true,
actions: [
Switch(
value: _isDark,
onChanged: (v) => setState(() => _isDark = v),
activeThumbColor: Colors.white,
),
],
),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
_Section(
label: 'OUTLINED',
child: SmartTextField(
style: FieldStyle.outlined,
hintText: 'Outlined field',
labelText: 'Email',
prefixIcon: Icons.email_outlined,
themeOverride: theme,
),
),
_Section(
label: 'FILLED',
child: SmartTextField(
style: FieldStyle.filled,
hintText: 'Filled field',
labelText: 'Password',
inputType: AppInputType.password,
themeOverride: theme,
),
),
_Section(
label: 'ROUNDED',
child: SmartTextField(
style: FieldStyle.rounded,
hintText: 'Rounded field',
labelText: 'Phone',
prefixIcon: Icons.phone_outlined,
themeOverride: theme,
),
),
_Section(
label: 'CUSTOM PURPLE THEME',
child: SmartTextField(
style: FieldStyle.outlined,
hintText: 'Custom theme field',
labelText: 'Custom',
prefixIcon: Icons.palette_outlined,
themeOverride: SmartTextFieldTheme(
borderRadius: 20,
borderColor: Colors.purple.shade200,
focusedBorderColor: Colors.purple,
filledColor: Colors.purple.shade50,
textColor: Colors.purple.shade900,
hintColor: Colors.purple.shade300,
labelColor: Colors.purple,
iconColor: Colors.purple,
),
),
),
],
),
),
);
}
}
// ── Screen 7: Login Screen ───────────────────────────────────
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _isLoading = false;
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
void _login() async {
if (_formKey.currentState!.validate()) {
setState(() => _isLoading = true);
await Future.delayed(const Duration(seconds: 2));
setState(() => _isLoading = false);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('✅ Login Successful!'),
backgroundColor: Colors.green,
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 48),
const Text(
'Welcome Back 👋',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 8),
Text(
'Sign in to your account',
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 48),
SmartTextFormField.email(
controller: _emailController,
validator: SmartValidators.email,
style: FieldStyle.outlined,
),
const SizedBox(height: 16),
SmartTextFormField.password(
controller: _passwordController,
validator: SmartValidators.required(),
style: FieldStyle.outlined,
),
const SizedBox(height: 12),
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {},
child: const Text('Forgot Password?'),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 52,
child: ElevatedButton(
onPressed: _isLoading ? null : _login,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
),
child: _isLoading
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
)
: const Text(
'Sign In',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account? ",
style: TextStyle(color: Colors.grey.shade600),
),
TextButton(
onPressed: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => const RegisterScreen(),
),
),
child: const Text('Sign Up'),
),
],
),
],
),
),
),
),
);
}
}
// ── Screen 8: Register Screen ────────────────────────────────
class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key});
@override
State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final _formKey = GlobalKey<FormState>();
final _passwordController = TextEditingController();
bool _isLoading = false;
@override
void dispose() {
_passwordController.dispose();
super.dispose();
}
void _register() async {
if (_formKey.currentState!.validate()) {
setState(() => _isLoading = true);
await Future.delayed(const Duration(seconds: 2));
setState(() => _isLoading = false);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('✅ Account Created Successfully!'),
backgroundColor: Colors.green,
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 48),
const Text(
'Create Account ✨',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 8),
Text(
'Fill in your details to get started',
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 36),
SmartTextFormField(
inputType: AppInputType.name,
labelText: 'Full Name',
hintText: 'Enter your full name',
prefixIcon: Icons.person_outline,
validator: SmartValidators.name,
),
const SizedBox(height: 16),
SmartTextFormField(
inputType: AppInputType.username,
labelText: 'Username',
hintText: 'Choose a username',
prefixIcon: Icons.alternate_email,
validator: SmartValidators.username,
helperText: 'Letters, numbers and underscores only',
),
const SizedBox(height: 16),
SmartTextFormField.email(
validator: SmartValidators.email,
),
const SizedBox(height: 16),
SmartTextFormField.phone(
validator: SmartValidators.phone,
),
const SizedBox(height: 16),
SmartTextFormField.password(
controller: _passwordController,
validator: SmartValidators.password,
),
const SizedBox(height: 16),
SmartTextFormField(
inputType: AppInputType.password,
labelText: 'Confirm Password',
hintText: 'Re-enter your password',
validator: SmartValidators.confirmPassword(
_passwordController.text,
),
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
height: 52,
child: ElevatedButton(
onPressed: _isLoading ? null : _register,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
),
child: _isLoading
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
)
: const Text(
'Create Account',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Already have an account? ',
style: TextStyle(color: Colors.grey.shade600),
),
TextButton(
onPressed: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => const LoginScreen(),
),
),
child: const Text('Sign In'),
),
],
),
],
),
),
),
),
);
}
}