smart_phone_number 1.0.2
smart_phone_number: ^1.0.2 copied to clipboard
A smart phone number parser that automatically detects country codes from number prefixes and validates WhatsApp accounts
example/main.dart
import 'package:flutter/material.dart';
import 'package:smart_phone_number/smart_phone_number.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Phone Validator Example',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: PhoneValidatorExample(),
);
}
}
class PhoneValidatorExample extends StatefulWidget {
const PhoneValidatorExample({super.key});
@override
_PhoneValidatorExampleState createState() => _PhoneValidatorExampleState();
}
class _PhoneValidatorExampleState extends State<PhoneValidatorExample> {
final TextEditingController _controller = TextEditingController();
String _result = '';
bool _loading = false;
String _selectedMethod = 'Auto Detect';
final List<String> _methods = [
'Auto Detect',
'Specific Country',
'Force Country',
];
String _selectedCountry = '967'; // Yemen default
final List<Map<String, String>> _countries = [
{'code': '967', 'name': 'š¾šŖ Yemen'},
{'code': '966', 'name': 'šøš¦ Saudi Arabia'},
{'code': '962', 'name': 'šÆš“ Jordan'},
{'code': '20', 'name': 'šŖš¬ Egypt'},
{'code': '964', 'name': 'š®š¶ Iraq'},
{'code': '971', 'name': 'š¦šŖ UAE'},
{'code': '965', 'name': 'š°š¼ Kuwait'},
{'code': '974', 'name': 'š¶š¦ Qatar'},
{'code': '973', 'name': 'š§š Bahrain'},
{'code': '968', 'name': 'š“š² Oman'},
{'code': '961', 'name': 'š±š§ Lebanon'},
{'code': '970', 'name': 'šµšø Palestine'},
{'code': '218', 'name': 'š±š¾ Libya'},
{'code': '216', 'name': 'š¹š³ Tunisia'},
{'code': '213', 'name': 'š©šæ Algeria'},
{'code': '212', 'name': 'š²š¦ Morocco'},
{'code': '1', 'name': 'šŗšø USA'},
{'code': '44', 'name': 'š¬š§ UK'},
{'code': '49', 'name': 'š©šŖ Germany'},
{'code': '33', 'name': 'š«š· France'},
{'code': '39', 'name': 'š®š¹ Italy'},
{'code': '34', 'name': 'šŖšø Spain'},
{'code': '90', 'name': 'š¹š· Turkey'},
{'code': '91', 'name': 'š®š³ India'},
];
Future<void> _validateNumber() async {
if (_controller.text.isEmpty) {
setState(() => _result = 'ā ļø Please enter a phone number');
return;
}
setState(() {
_loading = true;
_result = '';
});
try {
PhoneResult result;
switch (_selectedMethod) {
case 'Auto Detect':
result = await SmartPhoneNumber.detectAndValidate(_controller.text);
break;
case 'Specific Country':
result = await SmartPhoneNumber.validateWithCountryCode(
phoneNumber: _controller.text,
countryCode: _selectedCountry,
);
break;
case 'Force Country':
result = await SmartPhoneNumber.validateWithCountryCode(
phoneNumber: _controller.text,
countryCode: _selectedCountry,
forceCountryCode: true,
);
break;
default:
result = await SmartPhoneNumber.detectAndValidate(_controller.text);
}
setState(() {
if (result.success) {
_result =
'''
ā
WhatsApp Account Found!
š± Phone: ${result.phoneNumber}
š Country Code: +${result.countryCode}
š Region: ${result.regionCode}
š” Tip: You can now open WhatsApp and start chatting!
''';
} else {
_result = 'ā ${result.message}';
if (result.possibleCountries != null &&
result.possibleCountries!.isNotEmpty) {
_result += '\n\nš Possible Countries:';
for (var country in result.possibleCountries!) {
_result +=
'\n⢠${country.nameAr} (${country.name}) - +${country.code}';
}
}
if (result.possibleNumbers != null &&
result.possibleNumbers!.isNotEmpty) {
_result += '\n\nš Possible Formats:';
for (var number in result.possibleNumbers!) {
_result += '\n⢠$number';
}
}
}
});
} catch (e) {
setState(() => _result = 'ā Error: $e');
} finally {
setState(() => _loading = false);
}
}
void _clearAll() {
_controller.clear();
setState(() => _result = '');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('š± Phone Validator'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
actions: [
IconButton(
icon: Icon(Icons.help_outline),
onPressed: () => _showHelpDialog(),
),
],
),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Method Selection
Card(
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Validation Method',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
SegmentedButton<String>(
segments: _methods.map((method) {
return ButtonSegment<String>(
value: method,
label: Text(method),
);
}).toList(),
selected: {_selectedMethod},
onSelectionChanged: (Set<String> selection) {
setState(() {
_selectedMethod = selection.first;
});
},
),
if (_selectedMethod != 'Auto Detect') ...[
SizedBox(height: 12),
DropdownButtonFormField<String>(
initialValue: _selectedCountry,
decoration: InputDecoration(
labelText: 'Select Country',
border: OutlineInputBorder(),
),
items: _countries.map((country) {
return DropdownMenuItem<String>(
value: country['code'],
child: Text(country['name']!),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCountry = value!;
});
},
),
if (_selectedMethod == 'Force Country')
Padding(
padding: EdgeInsets.only(top: 8),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.orange.shade50,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.orange),
),
child: Row(
children: [
Icon(Icons.info_outline, color: Colors.orange),
SizedBox(width: 8),
Expanded(
child: Text(
'ā ļø Will force using +$_selectedCountry even if number has another prefix',
style: TextStyle(fontSize: 12),
),
),
],
),
),
),
],
],
),
),
),
SizedBox(height: 16),
// Phone Input
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Enter phone number',
hintText: 'e.g., 712345678 or +967712345678',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.phone),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: _clearAll,
),
),
keyboardType: TextInputType.phone,
onSubmitted: (_) => _validateNumber(),
),
SizedBox(height: 16),
// Validate Button
ElevatedButton(
onPressed: _loading ? null : _validateNumber,
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
child: _loading
? SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.check_circle_outline),
SizedBox(width: 8),
Text('Validate Number'),
],
),
),
SizedBox(height: 16),
// Result Container
Expanded(
child: Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
color: Colors.grey.shade50,
),
child: _result.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.phone_android,
size: 48,
color: Colors.grey.shade400,
),
SizedBox(height: 8),
Text(
'Enter a phone number and tap Validate',
style: TextStyle(color: Colors.grey.shade600),
),
],
),
)
: SingleChildScrollView(
child: Text(
_result,
style: TextStyle(fontSize: 14, height: 1.5),
),
),
),
),
],
),
),
);
}
void _showHelpDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('How to Use'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'1. Enter a phone number',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
' ⢠Can be local (712345678) or international (+967712345678)',
),
SizedBox(height: 8),
Text(
'2. Choose validation method',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(' ⢠Auto Detect: Automatically detects country'),
Text(' ⢠Specific Country: Use your chosen country'),
Text(
' ⢠Force Country: Force country code even if number has another',
),
SizedBox(height: 8),
Text(
'3. Tap Validate',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(' ⢠Checks if number exists on WhatsApp'),
Text(' ⢠Shows country info and possible formats'),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Got it!'),
),
],
),
);
}
}