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

Flutter widget that handle OTP resend functionality with customizable UI, animations, and callback support.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:otp_resend_timer/otp_resend_timer.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'OTP Resend Timer Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late OtpResendTimerController _controller;
  final TextEditingController _otpController = TextEditingController();
  final List<FocusNode> _focusNodes = List.generate(4, (index) => FocusNode());
  final List<TextEditingController> _digitControllers = 
      List.generate(4, (index) => TextEditingController());
  
  @override
  void initState() {
    super.initState();
    _controller = OtpResendTimerController(initialTime: 10);
  }
  
  @override
  void dispose() {
    _controller.dispose();
    _otpController.dispose();
    for (var node in _focusNodes) {
      node.dispose();
    }
    for (var controller in _digitControllers) {
      controller.dispose();
    }
    super.dispose();
  }
  
  void _onResendClicked() {
    // Resend OTP logic here
  }

  void _onDigitInput(String value, int index) {
    if (value.length == 1) {
      if (index < 3) {
        _focusNodes[index + 1].requestFocus();
      } else {
        // Last digit entered, hide keyboard
        FocusManager.instance.primaryFocus?.unfocus();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    
    return Scaffold(
      appBar: AppBar(
        backgroundColor: theme.colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const SizedBox(height: 30),
              // Example of a mock OTP input field
              Container(
                margin: const EdgeInsets.symmetric(horizontal: 24),
                padding: const EdgeInsets.all(24),
                decoration: BoxDecoration(
                  color: Colors.white,
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(12),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.grey.shade200,
                      blurRadius: 10,
                      offset: const Offset(0, 5),
                    ),
                  ],
                ),
                child: Column(
                  children: [
                    const Text(
                      'Enter OTP Code',
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 10),
                    const Text(
                      'We\'ve sent a verification code to your phone',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey,
                      ),
                    ),
                    const SizedBox(height: 30),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: List.generate(
                        4,
                        (index) => SizedBox(
                          width: 50,
                          height: 60,
                          child: TextField(
                            controller: _digitControllers[index],
                            focusNode: _focusNodes[index],
                            textAlign: TextAlign.center,
                            keyboardType: TextInputType.number,
                            maxLength: 1,
                            onChanged: (value) => _onDigitInput(value, index),
                            decoration: InputDecoration(
                              counterText: '',
                              contentPadding: EdgeInsets.zero,
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(8),
                                borderSide: BorderSide(color: theme.primaryColor),
                              ),
                              focusedBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(8),
                                borderSide: BorderSide(color: theme.primaryColor, width: 2),
                              ),
                            ),
                            style: const TextStyle(
                              fontSize: 24,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(height: 30),
                    SizedBox(
                      width: double.infinity,
                      child: ElevatedButton(
                        onPressed: () {
                          // String otp = _digitControllers.map((c) => c.text).join();
                        },
                        style: ElevatedButton.styleFrom(
                          backgroundColor: theme.primaryColor,
                          foregroundColor: Colors.white,
                          padding: const EdgeInsets.symmetric(vertical: 12),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(8),
                          ),
                        ),
                        child: const Text('Verify'),
                      ),
                    ),
                    const SizedBox(height: 20),
                    
                    // OtpResendTimer
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 8.0),
                      child: OtpResendTimer(
                        controller: _controller,
                        onResendClicked: _onResendClicked,
                        autoStart: true,
                        timerMessage: 'Resend OTP in ',
                        readyMessage: 'You can now resend the code',
                        holdMessage: 'Start timer to enable resend',
                        resendMessage: 'Resend',
                        timerMessageStyle: TextStyle(
                          color: theme.primaryColor,
                          fontSize: 12,
                        ),
                        resendMessageStyle: TextStyle(
                          color: theme.primaryColor,
                          fontSize: 12,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
11
likes
150
points
35
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Flutter widget that handle OTP resend functionality with customizable UI, animations, and callback support.

Repository (GitHub)
View/report issues

Topics

#flutter #dart #otp #animation #resend

License

MIT (license)

Dependencies

flutter

More

Packages that depend on otp_resend_timer