225 lines
6.7 KiB
Dart
225 lines
6.7 KiB
Dart
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<PaymentMethod> _recipientMethods = [];
|
|
Recipient? _recipient;
|
|
String? _selectedMethodId;
|
|
|
|
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 {
|
|
if (!hasRecipient) return null;
|
|
if (_selectedMethodId != null) {
|
|
final byId = _recipientMethods.firstWhereOrNull((method) => method.id == _selectedMethodId);
|
|
if (byId != null) return byId;
|
|
}
|
|
return _preferredMethodForType(_selectedType, _recipientMethods);
|
|
}
|
|
|
|
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<PaymentMethod> get methodsForRecipient => hasRecipient
|
|
? List<PaymentMethod>.unmodifiable(_recipientMethods)
|
|
: const [];
|
|
|
|
List<PaymentMethod> get methodsForSelectedType => hasRecipient
|
|
? List<PaymentMethod>.unmodifiable(
|
|
_recipientMethods.where((method) => method.type == _selectedType).toList(),
|
|
)
|
|
: 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 (hasRecipient) {
|
|
_selectedMethodId = _preferredMethodForType(type, _recipientMethods)?.id;
|
|
}
|
|
if (resetManualData) {
|
|
_manualPaymentData = null;
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
void selectMethod(PaymentMethod method) {
|
|
if (!hasRecipient) return;
|
|
if (_selectedMethodId == method.id && _selectedType == method.type) return;
|
|
_selectedMethodId = method.id;
|
|
if (_selectedType != method.type) {
|
|
_selectedType = method.type;
|
|
}
|
|
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<PaymentMethod> methods,
|
|
required PaymentType? preferredType,
|
|
required bool forceResetManualData,
|
|
}) {
|
|
final availableTypes = _buildAvailableTypes(methods);
|
|
final resolvedType = _resolveSelectedType(
|
|
recipient: recipient,
|
|
availableTypes: availableTypes,
|
|
preferredType: preferredType,
|
|
);
|
|
final resolvedMethod = _resolveSelectedMethod(
|
|
recipient: recipient,
|
|
methods: methods,
|
|
selectedType: resolvedType,
|
|
selectedMethodId: _selectedMethodId,
|
|
);
|
|
|
|
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 ((resolvedMethod?.id ?? _selectedMethodId) != _selectedMethodId) {
|
|
_selectedMethodId = resolvedMethod?.id;
|
|
hasChanges = true;
|
|
}
|
|
|
|
if ((recipient != null || forceResetManualData) && _manualPaymentData != null) {
|
|
_manualPaymentData = null;
|
|
hasChanges = true;
|
|
}
|
|
|
|
if (hasChanges) notifyListeners();
|
|
}
|
|
|
|
MethodMap _buildAvailableTypes(List<PaymentMethod> methods) => {
|
|
for (final method in methods) method.type: method.data,
|
|
};
|
|
|
|
PaymentMethod? _preferredMethodForType(PaymentType type, List<PaymentMethod> methods) {
|
|
final forType = methods.where((method) => method.type == type).toList();
|
|
if (forType.isEmpty) return null;
|
|
return forType.firstWhereOrNull((method) => method.isMain) ?? forType.first;
|
|
}
|
|
|
|
PaymentMethod? _resolveSelectedMethod({
|
|
required Recipient? recipient,
|
|
required List<PaymentMethod> methods,
|
|
required PaymentType selectedType,
|
|
required String? selectedMethodId,
|
|
}) {
|
|
if (recipient == null) return null;
|
|
final forType = methods.where((method) => method.type == selectedType).toList();
|
|
if (forType.isEmpty) return null;
|
|
if (selectedMethodId != null) {
|
|
final byId = forType.firstWhereOrNull((method) => method.id == selectedMethodId);
|
|
if (byId != null) return byId;
|
|
}
|
|
return _preferredMethodForType(selectedType, methods);
|
|
}
|
|
|
|
bool _hasSameMethods(List<PaymentMethod> 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;
|
|
}
|
|
}
|