flutter_sms_otp_pro 1.0.0 copy "flutter_sms_otp_pro: ^1.0.0" to clipboard
flutter_sms_otp_pro: ^1.0.0 copied to clipboard

Enterprise-grade Flutter SMS OTP library with auto-read capabilities, beautiful UI components, and comprehensive platform support.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sms_otp_pro/flutter_sms_otp_pro.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SMS OTP Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.indigo, useMaterial3: true),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        primarySwatch: Colors.indigo,
        useMaterial3: true,
      ),
      home: const OtpDemoPage(),
    );
  }
}

class OtpDemoPage extends StatefulWidget {
  const OtpDemoPage({super.key});

  @override
  State<OtpDemoPage> createState() => _OtpDemoPageState();
}

class _OtpDemoPageState extends State<OtpDemoPage> {
  late OtpController _otpController;
  String? _appSignature;
  String _selectedStyle = 'rounded';
  bool _isVerifying = false;
  String? _verificationResult;

  final _styles = {
    'rounded': OtpFieldStyle.rounded(),
    'underlined': OtpFieldStyle.underlined(),
    'boxed': OtpFieldStyle.boxed(),
    'circular': OtpFieldStyle.circular(),
    'glassmorphism': OtpFieldStyle.glassmorphism(),
    'dark': OtpFieldStyle.dark(),
  };

  @override
  void initState() {
    super.initState();
    _otpController = OtpController(
      config: const SmsOtpConfig(
        otpLength: 6,
        timeout: Duration(minutes: 5),
        maxRetries: 3,
        retryCooldown: Duration(seconds: 30),
      ),
    );
    _loadAppSignature();
    _startSmsListener();

    // Listen for OTP auto-fill from SMS
    _otpController.addListener(_onOtpStateChanged);
  }

  void _onOtpStateChanged() {
    // When OTP is auto-filled from SMS, call onCompleted
    if (_otpController.value.isComplete &&
        _otpController.value.otp.isNotEmpty) {
      _onOtpCompleted(_otpController.value.otp);
    }
  }

  Future<void> _startSmsListener() async {
    // Start listening for SMS (for Android auto-read)
    if (_otpController.supportsAutoRead) {
      await _otpController.startListening();
    }
  }

  Future<void> _loadAppSignature() async {
    final signature = await _otpController.getAppSignature();
    if (mounted) {
      setState(() {
        _appSignature = signature;
      });
    }
  }

  void _onOtpCompleted(String otp) {
    setState(() {
      _isVerifying = true;
      _verificationResult = null;
    });

    // Simulate verification delay
    Future.delayed(const Duration(seconds: 2), () {
      if (mounted) {
        setState(() {
          _isVerifying = false;
          // Simulate success if OTP is "123456"
          _verificationResult =
              otp == '123456' ? '✅ Verified successfully!' : '❌ Invalid OTP';
        });
      }
    });
  }

  void _resetOtp() {
    _otpController.reset();
    setState(() {
      _verificationResult = null;
      _isVerifying = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;

    return Scaffold(
      appBar: AppBar(
        title: const Text('SMS OTP Demo'),
        centerTitle: true,
        elevation: 0,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Style Selector
            _buildSectionTitle('Style'),
            const SizedBox(height: 12),
            SizedBox(
              height: 40,
              child: ListView.builder(
                scrollDirection: Axis.horizontal,
                itemCount: _styles.length,
                itemBuilder: (context, index) {
                  final styleName = _styles.keys.elementAt(index);
                  final isSelected = styleName == _selectedStyle;
                  return Padding(
                    padding: const EdgeInsets.only(right: 8),
                    child: FilterChip(
                      label: Text(styleName),
                      selected: isSelected,
                      onSelected: (_) {
                        setState(() => _selectedStyle = styleName);
                        _resetOtp();
                        _startSmsListener(); // Restart SMS listener
                      },
                    ),
                  );
                },
              ),
            ),

            const SizedBox(height: 32),

            // OTP Input Section
            _buildSectionTitle('Enter OTP'),
            const SizedBox(height: 8),
            Text(
              'Enter the 6-digit code sent to your phone',
              style: TextStyle(color: Colors.grey[600], fontSize: 14),
            ),
            const SizedBox(height: 24),

            // OTP Field with dynamic background
            Container(
              width: double.infinity,
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
              decoration: BoxDecoration(
                gradient: _selectedStyle == 'glassmorphism'
                    ? LinearGradient(
                        colors: [
                          Colors.indigo.shade400,
                          Colors.purple.shade400,
                        ],
                        begin: Alignment.topLeft,
                        end: Alignment.bottomRight,
                      )
                    : null,
                color: _selectedStyle == 'dark'
                    ? const Color(0xFF111827)
                    : (_selectedStyle != 'glassmorphism'
                        ? (isDark ? Colors.grey[900] : Colors.grey[50])
                        : null),
                borderRadius: BorderRadius.circular(16),
              ),
              child: OtpField(
                key: ValueKey(_selectedStyle), // Force rebuild on style change
                length: 6,
                controller: _otpController,
                style: _styles[_selectedStyle],
                autoFocus: true,
                hapticFeedback: true,
                onCompleted: _onOtpCompleted,
                onChanged: (value) {
                  if (_verificationResult != null) {
                    setState(() => _verificationResult = null);
                  }
                },
              ),
            ),

            const SizedBox(height: 24),

            // Verification Status
            if (_isVerifying)
              const Center(
                child: Column(
                  children: [
                    CircularProgressIndicator(),
                    SizedBox(height: 12),
                    Text('Verifying...'),
                  ],
                ),
              )
            else if (_verificationResult != null)
              Center(
                child: Card(
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child: Text(
                      _verificationResult!,
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.w600,
                        color: _verificationResult!.contains('✅')
                            ? Colors.green
                            : Colors.red,
                      ),
                    ),
                  ),
                ),
              ),

            const SizedBox(height: 24),

            // Countdown Timer
            Center(
              child: CountdownTimer(
                duration: const Duration(seconds: 30),
                onResend: () {
                  _resetOtp();
                  _startSmsListener(); // Restart SMS listener
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('OTP resent! SMS listener started.'),
                      duration: Duration(seconds: 2),
                    ),
                  );
                },
              ),
            ),

            const SizedBox(height: 32),

            // Phone Input Section
            _buildSectionTitle('Phone Number'),
            const SizedBox(height: 16),
            PhoneField(
              initialCountryCode: '+1',
              labelText: 'Mobile Number',
              hintText: 'Enter phone number',
              showValidation: true,
              onValidated: (result) {
                if (result.isValid) {
                  debugPrint('Valid: ${result.e164Format}');
                }
              },
            ),

            const SizedBox(height: 32),

            // App Signature Section (Android only)
            if (_appSignature != null) ...[
              _buildSectionTitle('Android App Signature'),
              const SizedBox(height: 8),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Include this in your SMS for auto-read:',
                        style: TextStyle(fontSize: 12),
                      ),
                      const SizedBox(height: 8),
                      Row(
                        children: [
                          Expanded(
                            child: SelectableText(
                              _appSignature!,
                              style: const TextStyle(
                                fontFamily: 'monospace',
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ),
                          IconButton(
                            icon: const Icon(Icons.copy, size: 20),
                            tooltip: 'Copy signature',
                            onPressed: () {
                              Clipboard.setData(
                                  ClipboardData(text: _appSignature!));
                              ScaffoldMessenger.of(context).showSnackBar(
                                const SnackBar(
                                  content: Text('Signature copied!'),
                                  duration: Duration(seconds: 2),
                                ),
                              );
                            },
                          ),
                        ],
                      ),
                      const SizedBox(height: 12),
                      const Divider(),
                      const SizedBox(height: 8),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          const Text(
                            'SMS Format:',
                            style: TextStyle(
                              fontSize: 13,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                          TextButton.icon(
                            onPressed: () {
                              final smsFormat =
                                  '<#> Your code is 123456\n$_appSignature';
                              Clipboard.setData(ClipboardData(text: smsFormat));
                              ScaffoldMessenger.of(context).showSnackBar(
                                const SnackBar(
                                  content: Text('SMS format copied!'),
                                  duration: Duration(seconds: 2),
                                ),
                              );
                            },
                            icon: const Icon(Icons.copy, size: 16),
                            label: const Text('Copy'),
                          ),
                        ],
                      ),
                      const SizedBox(height: 4),
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: Colors.grey.shade100,
                          borderRadius: BorderRadius.circular(8),
                          border: Border.all(
                            color: Colors.grey.shade300,
                          ),
                        ),
                        child: Text(
                          '<#> Your code is 123456\n$_appSignature',
                          style: const TextStyle(
                            fontFamily: 'monospace',
                            fontSize: 11,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],

            const SizedBox(height: 24),

            // Reset Button
            Center(
              child: OutlinedButton.icon(
                onPressed: _resetOtp,
                icon: const Icon(Icons.refresh),
                label: const Text('Reset'),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSectionTitle(String title) {
    return Text(
      title,
      style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
    );
  }

  @override
  void dispose() {
    _otpController.removeListener(_onOtpStateChanged);
    _otpController.dispose();
    super.dispose();
  }
}
0
likes
150
points
--
downloads

Publisher

verified publishersitharaj.in

Enterprise-grade Flutter SMS OTP library with auto-read capabilities, beautiful UI components, and comprehensive platform support.

Topics

#otp #sms #authentication #verification #phone

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_sms_otp_pro

Packages that implement flutter_sms_otp_pro