import 'package:flutter/widgets.dart'; import 'package:fancy_password_field/fancy_password_field.dart'; import 'package:pweb/models/state/control_state.dart'; import 'package:pweb/widgets/password/hint/error.dart'; import 'package:pweb/widgets/password/hint/short.dart'; import 'package:pweb/widgets/password/password.dart'; import 'package:pweb/generated/i18n/app_localizations.dart'; class PasswordVeirificationRule extends ValidationRule { final String ruleName; final TextEditingController externalPasswordController; PasswordVeirificationRule({ required this.ruleName, required this.externalPasswordController, }); @override String get name => ruleName; @override bool get showName => true; @override bool validate(String value) => value == externalPasswordController.text; } class VerifyPasswordField extends StatefulWidget { final ValueChanged? onValid; final TextEditingController controller; final TextEditingController externalPasswordController; final String? labelText; final ControlState state; const VerifyPasswordField({ super.key, this.onValid, required this.controller, required this.externalPasswordController, this.labelText, this.state = ControlState.enabled, }); @override State createState() => _VerifyPasswordFieldState(); } class _VerifyPasswordFieldState extends State { bool _isCurrentlyValid = false; @override void initState() { super.initState(); widget.controller.addListener(_validatePassword); widget.externalPasswordController.addListener(_validatePassword); } void _validatePassword() { final isValid = widget.controller.text == widget.externalPasswordController.text; // Only call onValid if the validity state has changed to prevent infinite loops if (isValid != _isCurrentlyValid) { setState(() { _isCurrentlyValid = isValid; }); widget.onValid?.call(isValid); } } @override Widget build(BuildContext context) { final isEnabled = widget.state == ControlState.enabled; final rule = PasswordVeirificationRule( ruleName: AppLocalizations.of(context)!.passwordsDoNotMatch, externalPasswordController: widget.externalPasswordController, ); return IgnorePointer( ignoring: !isEnabled, child: Opacity( opacity: isEnabled ? 1 : 0.6, child: defaulRulesPasswordField( context, controller: widget.controller, key: widget.key, labelText: widget.labelText ?? AppLocalizations.of(context)!.confirmPassword, additionalRules: {rule}, validationRuleBuilder: (rules, value) => rule.validate(value) ? shortValidation(context, rules, value) : PasswordValidationErrorLabel( labelText: AppLocalizations.of(context)!.passwordsDoNotMatch, ), onValid: widget.onValid, ), ), ); } @override void dispose() { widget.controller.removeListener(_validatePassword); widget.externalPasswordController.removeListener(_validatePassword); super.dispose(); } }