// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flutter code sample for Action.Action.overridable

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

void main() {
  runApp(
    const MaterialApp(
      home: Scaffold(
        body: Center(child: SimpleUSPhoneNumberEntry()),
      ),
    ),
  );
}

// This implements a custom phone number input field that handles the
// [DeleteTextIntent] intent.
class DigitInput extends StatefulWidget {
  const DigitInput({
    Key? key,
    required this.controller,
    required this.focusNode,
    this.maxLength,
    this.textInputAction = TextInputAction.next,
  }) : super(key: key);

  final int? maxLength;
  final TextEditingController controller;
  final TextInputAction textInputAction;
  final FocusNode focusNode;

  @override
  DigitInputState createState() => DigitInputState();
}

class DigitInputState extends State<DigitInput> {
  late final Action<DeleteTextIntent> _deleteTextAction =
      CallbackAction<DeleteTextIntent>(
    onInvoke: (DeleteTextIntent intent) {
      // For simplicity we delete everything in the section.
      widget.controller.clear();
    },
  );

  @override
  Widget build(BuildContext context) {
    return Actions(
      actions: <Type, Action<Intent>>{
        // Make the default `DeleteTextIntent` handler overridable.
        DeleteTextIntent: Action<DeleteTextIntent>.overridable(
            defaultAction: _deleteTextAction, context: context),
      },
      child: TextField(
        controller: widget.controller,
        textInputAction: TextInputAction.next,
        keyboardType: TextInputType.phone,
        focusNode: widget.focusNode,
        decoration: const InputDecoration(
          border: OutlineInputBorder(),
        ),
        inputFormatters: <TextInputFormatter>[
          FilteringTextInputFormatter.digitsOnly,
          LengthLimitingTextInputFormatter(widget.maxLength),
        ],
      ),
    );
  }
}

class SimpleUSPhoneNumberEntry extends StatefulWidget {
  const SimpleUSPhoneNumberEntry({Key? key}) : super(key: key);

  @override
  State<SimpleUSPhoneNumberEntry> createState() =>
      _SimpleUSPhoneNumberEntryState();
}

class _DeleteDigit extends Action<DeleteTextIntent> {
  _DeleteDigit(this.state);

  final _SimpleUSPhoneNumberEntryState state;
  @override
  Object? invoke(DeleteTextIntent intent) {
    assert(callingAction != null);
    callingAction?.invoke(intent);

    if (state.lineNumberController.text.isEmpty &&
        state.lineNumberFocusNode.hasFocus) {
      state.prefixFocusNode.requestFocus();
    }

    if (state.prefixController.text.isEmpty && state.prefixFocusNode.hasFocus) {
      state.areaCodeFocusNode.requestFocus();
    }
  }

  // This action is only enabled when the `callingAction` exists and is
  // enabled.
  @override
  bool get isActionEnabled => callingAction?.isActionEnabled ?? false;
}

class _SimpleUSPhoneNumberEntryState extends State<SimpleUSPhoneNumberEntry> {
  final FocusNode areaCodeFocusNode = FocusNode();
  final TextEditingController areaCodeController = TextEditingController();
  final FocusNode prefixFocusNode = FocusNode();
  final TextEditingController prefixController = TextEditingController();
  final FocusNode lineNumberFocusNode = FocusNode();
  final TextEditingController lineNumberController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Actions(
      actions: <Type, Action<Intent>>{
        DeleteTextIntent: _DeleteDigit(this),
      },
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          const Expanded(
            child: Text('(', textAlign: TextAlign.center),
          ),
          Expanded(
            flex: 3,
            child: DigitInput(
              focusNode: areaCodeFocusNode,
              controller: areaCodeController,
              maxLength: 3,
            ),
          ),
          const Expanded(
            child: Text(')', textAlign: TextAlign.center),
          ),
          Expanded(
            flex: 3,
            child: DigitInput(
              focusNode: prefixFocusNode,
              controller: prefixController,
              maxLength: 3,
            ),
          ),
          const Expanded(
            child: Text('-', textAlign: TextAlign.center),
          ),
          Expanded(
            flex: 4,
            child: DigitInput(
              focusNode: lineNumberFocusNode,
              controller: lineNumberController,
              textInputAction: TextInputAction.done,
              maxLength: 4,
            ),
          ),
        ],
      ),
    );
  }
}
