import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:pshared/models/payment/methods/data.dart'; import 'package:pshared/models/payment/methods/type.dart'; import 'package:pshared/models/payment/type.dart'; import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/recipient/pmethods.dart'; class PaymentFlowProvider extends ChangeNotifier { PaymentType _selectedType; PaymentType? _preferredType; PaymentMethodData? _manualPaymentData; List _recipientMethods = []; Recipient? _recipient; PaymentFlowProvider({ required PaymentType initialType, PaymentType? preferredType, }) : _selectedType = initialType, _preferredType = preferredType ?? initialType; PaymentType get selectedType => _selectedType; PaymentMethodData? get manualPaymentData => _manualPaymentData; Recipient? get recipient => _recipient; PaymentMethod? get selectedMethod => hasRecipient ? _recipientMethods.firstWhereOrNull((method) => method.type == _selectedType) : null; bool get hasRecipient => _recipient != null; MethodMap get availableTypes => hasRecipient ? _buildAvailableTypes(_recipientMethods) : {for (final type in PaymentType.values) type: null}; PaymentMethodData? get selectedPaymentData => hasRecipient ? selectedMethod?.data : _manualPaymentData; List get methodsForRecipient => hasRecipient ? List.unmodifiable(_recipientMethods) : const []; void update( RecipientsProvider recipientsProvider, PaymentMethodsProvider methodsProvider, ) => _applyState( recipient: recipientsProvider.currentObject, methods: methodsProvider.methodsForRecipient(recipientsProvider.currentObject), preferredType: _preferredType, forceResetManualData: false, ); void selectType(PaymentType type, {bool resetManualData = false}) { if (hasRecipient && !availableTypes.containsKey(type)) { return; } if (_selectedType == type && (!resetManualData || _manualPaymentData == null)) { return; } _selectedType = type; if (resetManualData) { _manualPaymentData = null; } notifyListeners(); } void setManualPaymentData(PaymentMethodData? data) { _manualPaymentData = data; notifyListeners(); } void setPreferredType(PaymentType? preferredType) { if (_preferredType == preferredType) { return; } _preferredType = preferredType; _applyState( recipient: _recipient, methods: _recipientMethods, preferredType: _preferredType, forceResetManualData: false, ); } PaymentType _resolveSelectedType({ required Recipient? recipient, required MethodMap availableTypes, PaymentType? preferredType, }) { if (recipient == null) { return preferredType ?? _selectedType; } if (availableTypes.isEmpty) { return preferredType ?? PaymentType.bankAccount; } if (availableTypes.keys.contains(_selectedType)) { return _selectedType; } if (preferredType != null && availableTypes.keys.contains(preferredType)) { return preferredType; } return availableTypes.keys.first; } void _applyState({ required Recipient? recipient, required List methods, required PaymentType? preferredType, required bool forceResetManualData, }) { final availableTypes = _buildAvailableTypes(methods); final resolvedType = _resolveSelectedType( recipient: recipient, availableTypes: availableTypes, preferredType: preferredType, ); var hasChanges = false; if (_recipient != recipient) { _recipient = recipient; hasChanges = true; } if (!_hasSameMethods(methods)) { _recipientMethods = methods; hasChanges = true; } if (resolvedType != _selectedType) { _selectedType = resolvedType; hasChanges = true; } if ((recipient != null || forceResetManualData) && _manualPaymentData != null) { _manualPaymentData = null; hasChanges = true; } if (hasChanges) notifyListeners(); } MethodMap _buildAvailableTypes(List methods) => { for (final method in methods) method.type: method.data, }; bool _hasSameMethods(List methods) { if (_recipientMethods.length != methods.length) return false; for (var i = 0; i < methods.length; i++) { final current = _recipientMethods[i]; final next = methods[i]; if (current.id != next.id || current.updatedAt != next.updatedAt) return false; } return true; } }