input_forms 0.0.4
input_forms: ^0.0.4 copied to clipboard
A comprehensive Flutter input_forms package providing pre-built, customizable form components for rapid application development. Includes email, password, date picker, and more form fields with built- [...]
import 'package:flutter/material.dart';
import 'package:input_forms/input_forms.dart';
void main() {
runApp(const InputFormsExampleApp());
}
class InputFormsExampleApp extends StatelessWidget {
const InputFormsExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Input Forms Package Demo',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: const InputFormsHomePage(),
);
}
}
class InputFormsHomePage extends StatefulWidget {
const InputFormsHomePage({Key? key}) : super(key: key);
@override
State<InputFormsHomePage> createState() => _InputFormsHomePageState();
}
class _InputFormsHomePageState extends State<InputFormsHomePage> {
int _currentIndex = 0;
final List<Widget> _pages = [
const BasicFormPage(),
const AdvancedFormPage(),
const EnterpriseFormPage(),
const FeatureShowcasePage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Input Forms Package Demo'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
elevation: 2,
),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.edit_outlined),
label: 'Basic Forms',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings_outlined),
label: 'Advanced',
),
BottomNavigationBarItem(
icon: Icon(Icons.business_outlined),
label: 'Enterprise',
),
BottomNavigationBarItem(
icon: Icon(Icons.star_outlined),
label: 'Showcase',
),
],
),
);
}
}
// Basic Form Page - Demonstrates core fields
class BasicFormPage extends StatefulWidget {
const BasicFormPage({Key? key}) : super(key: key);
@override
State<BasicFormPage> createState() => _BasicFormPageState();
}
class _BasicFormPageState extends State<BasicFormPage> {
final _formKey = GlobalKey<FormState>();
final _controllers = <String, TextEditingController>{};
String? _selectedCountry;
@override
void initState() {
super.initState();
// Initialize controllers
for (final field in [
'email',
'password',
'confirmPassword',
'username',
'phone',
'dob',
]) {
_controllers[field] = TextEditingController();
}
}
@override
void dispose() {
_controllers.values.forEach((controller) => controller.dispose());
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Basic Form Fields',
style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Demonstrates core input form components with validation.',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]),
),
],
),
),
),
const SizedBox(height: 24),
// Email Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Email Field',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
EmailField(
controller: _controllers['email'],
label: 'Business Email',
),
],
),
),
),
const SizedBox(height: 16),
// Password Fields
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Password Fields',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
PasswordField(
controller: _controllers['password'],
label: 'Password',
),
const SizedBox(height: 16),
ConfirmPasswordField(
passwordController: _controllers['password'],
confirmController: _controllers['confirmPassword'],
),
],
),
),
),
const SizedBox(height: 16),
// Username Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Username Field',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
UsernameField(
controller: _controllers['username'],
validator: (value) {
if (value == null || value.length < 3) {
return 'Username must be at least 3 characters';
}
if (!RegExp(r'^[a-zA-Z0-9_]+$').hasMatch(value)) {
return 'Only letters, numbers, and underscores allowed';
}
return null;
},
),
],
),
),
),
const SizedBox(height: 16),
// Phone Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'International Phone Field',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
PhoneField(
controller: _controllers['phone'],
label: 'Phone Number',
initialCountryCode: '+1',
),
],
),
),
),
const SizedBox(height: 16),
// Date Fields
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Date Fields',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
DOBField(
controller: _controllers['dob'],
label: 'Date of Birth',
),
],
),
),
),
const SizedBox(height: 16),
// Dropdown Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Dropdown Field',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
DropdownField<String>(
label: 'Country',
items: const [
'United States',
'Canada',
'United Kingdom',
'Australia',
'Germany',
'France',
'Japan',
'India',
],
value: _selectedCountry,
itemLabel: (item) => item,
onChanged: (value) =>
setState(() => _selectedCountry = value),
),
],
),
),
),
const SizedBox(height: 32),
// Submit Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_showSuccessDialog('Basic Form');
}
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
),
child: const Text('Submit Basic Form'),
),
),
],
),
),
);
}
void _showSuccessDialog(String formType) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('$formType Submitted!'),
content: const Text('All validations passed successfully.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
// Advanced Form Page - Demonstrates searchable dropdowns and location
class AdvancedFormPage extends StatefulWidget {
const AdvancedFormPage({Key? key}) : super(key: key);
@override
State<AdvancedFormPage> createState() => _AdvancedFormPageState();
}
class _AdvancedFormPageState extends State<AdvancedFormPage> {
final _formKey = GlobalKey<FormState>();
String? _selectedSkill;
List<String> _selectedLanguages = [];
LocationData? _selectedLocation;
final _skills = [
'Flutter Development',
'React Development',
'Node.js Development',
'Python Development',
'Java Development',
'DevOps Engineering',
'Data Science',
'Machine Learning',
'UI/UX Design',
'Product Management',
];
final _languages = [
'English',
'Spanish',
'French',
'German',
'Chinese',
'Japanese',
'Portuguese',
'Russian',
'Arabic',
'Hindi',
];
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Advanced Form Fields',
style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Features searchable dropdowns and location selection.',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]),
),
],
),
),
),
const SizedBox(height: 24),
// Searchable Dropdown
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Searchable Dropdown',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
SearchableDropdownField<String>(
label: 'Primary Skill',
items: _skills,
value: _selectedSkill,
itemLabel: (item) => item,
onChanged: (value) =>
setState(() => _selectedSkill = value),
searchHintText: 'Search skills...',
),
],
),
),
),
const SizedBox(height: 16),
// Multi-Select Searchable Dropdown
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Multi-Select Searchable Dropdown',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
SearchableDropdownField<String>(
label: 'Languages',
items: _languages,
enableMultiSelect: true,
selectedValues: _selectedLanguages,
itemLabel: (item) => item,
onMultiSelectChanged: (values) =>
setState(() => _selectedLanguages = values),
searchHintText: 'Search languages...',
showSelectedItemsChips: true,
maxSelectedItemsToShow: 3,
),
],
),
),
),
const SizedBox(height: 16),
// Location Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Location Field with Maps',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
LocationField(
label: 'Work Location',
value: _selectedLocation,
onChanged: (location) =>
setState(() => _selectedLocation = location),
mapProvider: MapProvider.openStreetMap,
enableLocationSearch: true,
enableMapSelection: true,
showCurrentLocationButton: true,
),
],
),
),
),
const SizedBox(height: 32),
// Submit Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_showResultDialog();
}
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
),
child: const Text('Submit Advanced Form'),
),
),
],
),
),
);
}
void _showResultDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Advanced Form Results'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Primary Skill: ${_selectedSkill ?? 'None'}'),
const SizedBox(height: 8),
Text('Languages: ${_selectedLanguages.join(', ')}'),
const SizedBox(height: 8),
Text('Location: ${_selectedLocation?.formattedAddress ?? 'None'}'),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
// Enterprise Form Page - Demonstrates file upload and signatures
class EnterpriseFormPage extends StatefulWidget {
const EnterpriseFormPage({Key? key}) : super(key: key);
@override
State<EnterpriseFormPage> createState() => _EnterpriseFormPageState();
}
class _EnterpriseFormPageState extends State<EnterpriseFormPage> {
final _formKey = GlobalKey<FormState>();
List<UploadedFile>? _uploadedDocuments;
SignatureData? _signature;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Enterprise Form Fields',
style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Advanced file upload and digital signature capabilities.',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]),
),
],
),
),
),
const SizedBox(height: 24),
// File Upload Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Advanced File Upload',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
FileUploadField(
label: 'Business Documents',
uploadMode: UploadMode.multiple,
allowedTypes: const [
FileType.document,
FileType.pdf,
FileType.image,
],
maxFiles: 5,
maxFileSize: 10 * 1024 * 1024, // 10MB
enableAIAnalysis: true,
showAdvancedInfo: true,
value: _uploadedDocuments,
onChanged: (files) =>
setState(() => _uploadedDocuments = files),
validator: (files) {
if (files == null || files.isEmpty) {
return 'Please upload at least one document';
}
return null;
},
),
],
),
),
),
const SizedBox(height: 16),
// Digital Signature Field
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Digital Signature',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
SignatureField(
label: 'Legal Signature',
signatureType: SignatureType.digital,
authLevel: AuthenticationLevel.enterprise,
enableBiometricCapture: true,
enableDigitalSigning: true,
showSignatureInfo: true,
showBiometricInfo: true,
value: _signature,
onChanged: (sig) => setState(() => _signature = sig),
validator: (signature) {
if (signature == null || signature.isEmpty) {
return 'Digital signature is required';
}
return null;
},
),
],
),
),
),
const SizedBox(height: 32),
// Submit Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_showEnterpriseResultDialog();
}
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
child: const Text('Submit Enterprise Form'),
),
),
],
),
),
);
}
void _showEnterpriseResultDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Enterprise Form Submitted'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Documents: ${_uploadedDocuments?.length ?? 0} files uploaded',
),
const SizedBox(height: 8),
Text(
'Signature: ${_signature?.isAuthenticated == true ? 'Digitally signed' : 'Basic signature'}',
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green[300]!),
),
child: Row(
children: [
Icon(Icons.security, color: Colors.green[600], size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
'Enterprise-grade security applied',
style: TextStyle(
color: Colors.green[700],
fontWeight: FontWeight.w500,
),
),
),
],
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
// Feature Showcase Page - Highlights all capabilities
class FeatureShowcasePage extends StatelessWidget {
const FeatureShowcasePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Input Forms Package',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'A comprehensive Flutter package for form inputs with advanced features.',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]),
),
],
),
),
),
const SizedBox(height: 24),
// Features Grid
_buildFeatureGrid(context),
const SizedBox(height: 24),
// Technical Specifications
_buildTechnicalSpecs(context),
],
),
);
}
Widget _buildFeatureGrid(BuildContext context) {
final features = [
_Feature(
'Email Validation',
'Advanced regex patterns with custom validation',
Icons.email,
Colors.blue,
),
_Feature(
'Password Security',
'Strength indicators and security requirements',
Icons.lock,
Colors.red,
),
_Feature(
'Phone Numbers',
'195+ countries with validation rules',
Icons.phone,
Colors.green,
),
_Feature(
'Search Dropdowns',
'Real-time filtering with multi-select',
Icons.search,
Colors.purple,
),
_Feature(
'Location Maps',
'Google Maps & OpenStreetMap integration',
Icons.location_on,
Colors.orange,
),
_Feature(
'File Upload',
'AI analysis with virus scanning',
Icons.upload_file,
Colors.teal,
),
_Feature(
'Digital Signatures',
'Biometric capture with encryption',
Icons.draw,
Colors.indigo,
),
_Feature(
'Date Pickers',
'Age validation and constraints',
Icons.calendar_today,
Colors.brown,
),
];
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.1,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: features.length,
itemBuilder: (context, index) {
final feature = features[index];
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: feature.color.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(feature.icon, color: feature.color, size: 32),
),
const SizedBox(height: 12),
Text(
feature.title,
style: Theme.of(
context,
).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
feature.description,
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: Colors.grey[600]),
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
},
);
}
Widget _buildTechnicalSpecs(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Technical Specifications',
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
_buildSpecItem(
'๐ฑ',
'Platform Support',
'iOS, Android, Web, Desktop',
),
_buildSpecItem(
'๐จ',
'UI Framework',
'Material Design 3 with custom theming',
),
_buildSpecItem(
'๐',
'Security',
'Encryption, Digital signatures, Biometrics',
),
_buildSpecItem(
'๐',
'Internationalization',
'RTL support, Multiple languages',
),
_buildSpecItem(
'โฟ',
'Accessibility',
'Screen reader support, Keyboard navigation',
),
_buildSpecItem('๐', 'Performance', 'Optimized for large datasets'),
_buildSpecItem(
'๐งช',
'Testing',
'Comprehensive unit and widget tests',
),
_buildSpecItem(
'๐ฆ',
'Package Size',
'Modular exports, Tree-shaking friendly',
),
],
),
),
);
}
Widget _buildSpecItem(String emoji, String title, String description) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(emoji, style: const TextStyle(fontSize: 20)),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
Text(
description,
style: TextStyle(color: Colors.grey[600], fontSize: 13),
),
],
),
),
],
),
);
}
}
class _Feature {
final String title;
final String description;
final IconData icon;
final Color color;
_Feature(this.title, this.description, this.icon, this.color);
}