123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- import 'dart:async';
- import 'package:fis_i18n/i18n.dart';
- import 'package:fis_measure/define.dart';
- import 'package:fis_measure/view/measure/measure_config/widgets/element_static.dart';
- import 'package:fis_measure/view/measure/measure_config/widgets/text_field.dart';
- import 'package:fis_ui/index.dart';
- import 'package:fis_ui/interface/interactive_container.dart';
- import 'package:flutter/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:fis_theme/theme.dart';
- /// 验证码表单栏控制器
- class VerificationCodeFieldController extends GetxController {
- VerificationCodeFieldController({
- this.countDown = 60,
- });
- final int countDown;
- Timer? _timer;
- bool _hasSent = false;
- final _seconds = 0.obs;
- final _isFetching = false.obs;
- final Rx<String> _btnText = Rx('');
- /// 倒计时读秒
- int get seconds => _seconds.value;
- set seconds(int val) => _seconds(val);
- /// 是否正在获取验证码
- bool get isFetching => _isFetching.value;
- set isFetching(bool val) => _isFetching(val);
- /// 按钮文字
- String get btnText => setBtnText();
- set btnText(String val) => _btnText(val);
- /// 按钮是否禁用
- bool get isBtnDisabled => isFetching || seconds > 0;
- /// 开启倒计时
- startCountDown() {
- _hasSent = true;
- seconds = countDown;
- _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
- seconds--;
- if (seconds == 0) {
- timer.cancel();
- }
- });
- }
- String setBtnText() {
- if (seconds > 0) {
- _btnText.value =
- i18nBook.auth.sendVerificationCodeTimer.translate([seconds]);
- } else {
- _btnText.value = _hasSent
- ? i18nBook.auth.resendVerificationCode.t
- : i18nBook.auth.sendVerificationCode.t;
- }
- return _btnText.value;
- }
- ///重置
- void reset() {
- if (_seconds.value == 0) {
- _timer?.cancel();
- _hasSent = false;
- _isFetching.value = false;
- setBtnText();
- }
- }
- @override
- void onClose() {
- _timer?.cancel();
- _timer = null;
- super.onClose();
- }
- }
- /// 验证码表单栏
- class VerificationCodeField extends StatelessWidget
- implements FInteractiveContainer {
- const VerificationCodeField({
- Key? key,
- this.tag,
- this.pageName = 'VerificationCodeField',
- required this.fetchCodeFunc,
- this.textController,
- this.textFocusNode,
- this.onTextChanged,
- this.disabled = false,
- this.inError = false,
- }) : super(key: key);
- @override
- final String pageName;
- final String? tag;
- final bool disabled;
- final Future<bool> Function() fetchCodeFunc;
- final TextEditingController? textController;
- final FocusNode? textFocusNode;
- final ValueChanged<String>? onTextChanged;
- final bool inError;
- @override
- FWidget build(BuildContext context) {
- if (kIsMobile) {
- return _MobileLayout(
- businessParent: this,
- tag: tag,
- disabled: disabled,
- fetchCodeFunc: fetchCodeFunc,
- textController: textController,
- textFocusNode: textFocusNode,
- onTextChanged: onTextChanged,
- inError: inError,
- );
- }
- final textField = _buildTextField(context);
- final button = _buildButton(context);
- return FFormField(builder: (state) {
- return FRow(
- children: [
- FExpanded(
- flex: 1,
- child: FContainer(
- margin: const EdgeInsets.only(right: 5),
- child: textField,
- ),
- ),
- QuickFWidget(button),
- ],
- );
- });
- }
- Widget _buildButton(BuildContext context) {
- final controller = Get.find<VerificationCodeFieldController>(tag: tag);
- const textStyle = TextStyle(
- fontSize: 14,
- color: Colors.white,
- height: 1,
- );
- final btnStyle = ElevatedButton.styleFrom(
- elevation: 0,
- padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16),
- minimumSize: const Size(120, 56),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(8),
- ),
- );
- onBtnTap() {
- controller.isFetching = true;
- fetchCodeFunc().then((value) {
- controller.isFetching = false;
- if (value) {
- controller.startCountDown();
- }
- });
- }
- return Obx(() {
- final isDisabled = disabled || controller.isBtnDisabled;
- final text = controller.btnText;
- return FElevatedButton(
- businessParent: this,
- onPressed: isDisabled ? null : onBtnTap,
- name: text,
- child: FText(
- text,
- style: textStyle,
- ),
- style: btnStyle,
- );
- });
- }
- FWidget _buildTextField(BuildContext context) {
- final border = FBorderTextFormField.createDesktopBorder(inError);
- final textField = FTextField(
- controller: textController,
- focusNode: textFocusNode,
- maxLength: 4,
- style: const TextStyle(fontSize: 18),
- keyboardType: TextInputType.number,
- inputFormatters: [PageInputFormatters.number],
- decoration: InputDecoration(
- hintText: i18nBook.auth.hint4VerificationCode.t,
- fillColor: TEXT_FIELD_FILL_COLOR,
- filled: true,
- hintStyle: const TextStyle(
- fontSize: 16,
- color: Colors.black54,
- ),
- alignLabelWithHint: true,
- counterText: '',
- isDense: true,
- contentPadding: FBorderTextFormField.createDesktopContentPadding(),
- enabledBorder: border,
- focusedBorder: border,
- ),
- onChanged: onTextChanged,
- );
- return textField;
- }
- }
- /// 验证码表单栏
- class _MobileLayout extends StatelessWidget implements FWidget {
- const _MobileLayout({
- this.tag,
- required this.fetchCodeFunc,
- this.textController,
- this.textFocusNode,
- this.onTextChanged,
- this.disabled = false,
- this.inError = false,
- required this.businessParent,
- });
- ///父级节点
- final FInteractiveContainer businessParent;
- final String? tag;
- final bool disabled;
- final Future<bool> Function() fetchCodeFunc;
- final TextEditingController? textController;
- final FocusNode? textFocusNode;
- final ValueChanged<String>? onTextChanged;
- final bool inError;
- @override
- FWidget build(BuildContext context) {
- final textField = _buildTextField(context);
- final button = _buildButton(context);
- return FFormField(builder: (state) {
- return FRow(
- children: [
- FExpanded(
- flex: 1,
- child: FContainer(
- margin: const EdgeInsets.only(right: 5),
- child: textField,
- ),
- ),
- if (kIsWeb)
- button
- else
- FContainer(
- height: 32,
- child: button,
- ),
- ],
- );
- });
- }
- FWidget _buildButton(BuildContext context) {
- final controller = Get.find<VerificationCodeFieldController>(tag: tag);
- const textStyle = TextStyle(
- fontSize: 14,
- color: Colors.white,
- );
- final btnStyle = ElevatedButton.styleFrom(
- elevation: 0,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(4),
- ),
- minimumSize: const Size.fromWidth(100),
- );
- onBtnTap() {
- controller.isFetching = true;
- fetchCodeFunc().then((value) {
- controller.isFetching = false;
- if (value) {
- controller.startCountDown();
- }
- });
- }
- return FObx(() {
- final isDisabled = disabled || controller.isBtnDisabled;
- final text = controller.btnText;
- return FElevatedButton(
- onPressed: isDisabled ? null : onBtnTap,
- name: text,
- businessParent: businessParent,
- child: FText(
- controller.btnText,
- style: textStyle,
- ),
- style: btnStyle,
- );
- });
- }
- FWidget _buildTextField(BuildContext context) {
- final border = OutlineInputBorder(
- borderRadius: const BorderRadius.all(Radius.circular(4)),
- borderSide: BorderSide(
- color: inError
- ? TEXT_FIELD_BORDER_ERROR_COLOR
- : FTheme.ins.data.colorScheme.line,
- ),
- );
- final textField = FTextField(
- controller: textController,
- focusNode: textFocusNode,
- maxLength: 4,
- keyboardType: TextInputType.number,
- decoration: InputDecoration(
- hintText: i18nBook.auth.hint4VerificationCode.t,
- fillColor: TEXT_FIELD_FILL_COLOR,
- filled: true,
- hintStyle: const TextStyle(
- fontSize: 12,
- color: Colors.black54,
- ),
- alignLabelWithHint: true,
- counterText: '',
- isDense: true,
- contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 26),
- enabledBorder: border,
- focusedBorder: border,
- ),
- onChanged: onTextChanged,
- );
- return textField;
- }
- }
|