generateOTPInput static method

String generateOTPInput()

Implementation

static String generateOTPInput() {
  return '''
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class OTPInput extends StatefulWidget {
final int length;
final Function(String) onCompleted;
final Function(String)? onChanged;

const OTPInput({
  Key? key,
  this.length = 6,
  required this.onCompleted,
  this.onChanged,
}) : super(key: key);

@override
State<OTPInput> createState() => _OTPInputState();
}

class _OTPInputState extends State<OTPInput> {
late List<TextEditingController> _controllers;
late List<FocusNode> _focusNodes;

@override
void initState() {
  super.initState();
  _controllers = List.generate(
    widget.length,
    (index) => TextEditingController(),
  );
  _focusNodes = List.generate(
    widget.length,
    (index) => FocusNode(),
  );
}

@override
void dispose() {
  for (var controller in _controllers) {
    controller.dispose();
  }
  for (var node in _focusNodes) {
    node.dispose();
  }
  super.dispose();
}

void _onChanged(String value, int index) {
  if (value.isNotEmpty && index < widget.length - 1) {
    _focusNodes[index + 1].requestFocus();
  }

  final otp = _controllers.map((c) => c.text).join();
  widget.onChanged?.call(otp);

  if (otp.length == widget.length) {
    widget.onCompleted(otp);
  }
}

void _onKeyEvent(RawKeyEvent event, int index) {
  if (event is RawKeyDownEvent &&
      event.logicalKey == LogicalKeyboardKey.backspace &&
      _controllers[index].text.isEmpty &&
      index > 0) {
    _focusNodes[index - 1].requestFocus();
  }
}

@override
Widget build(BuildContext context) {
  final theme = Theme.of(context);

  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: List.generate(
      widget.length,
      (index) => Expanded(
        child: Padding(
          padding: EdgeInsets.symmetric(
            horizontal: widget.length > 4 ? 4.0 : 8.0,
          ),
          child: RawKeyboardListener(
            focusNode: FocusNode(),
            onKey: (event) => _onKeyEvent(event, index),
            child: TextFormField(
              controller: _controllers[index],
              focusNode: _focusNodes[index],
              keyboardType: TextInputType.number,
              textAlign: TextAlign.center,
              maxLength: 1,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
              ],
              decoration: InputDecoration(
                counterText: '',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(16),
                  borderSide: BorderSide(
                    color: theme.colorScheme.outline,
                  ),
                ),
                enabledBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(16),
                  borderSide: BorderSide(
                    color: theme.colorScheme.outline.withOpacity(0.5),
                  ),
                ),
                focusedBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(16),
                  borderSide: BorderSide(
                    color: theme.colorScheme.primary,
                    width: 2,
                  ),
                ),
                filled: true,
                fillColor: theme.colorScheme.surfaceVariant.withOpacity(0.3),
                contentPadding: const EdgeInsets.symmetric(vertical: 16),
              ),
              onChanged: (value) => _onChanged(value, index),
            ),
          ),
        ),
      ),
    ),
  );
}
}
''';
}