Files
sendico/frontend/pweb/lib/controllers/payments/amount_field.dart

159 lines
4.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:pshared/controllers/balance_mask/wallets.dart';
import 'package:pshared/models/payment/settlement_mode.dart';
import 'package:pshared/provider/payment/amount.dart';
import 'package:pshared/utils/currency.dart';
import 'package:pshared/utils/money.dart';
import 'package:pweb/models/payment/amount/mode.dart';
class PaymentAmountFieldController extends ChangeNotifier {
static const String _settlementCurrencyCode = 'RUB';
final TextEditingController textController;
final FocusNode focusNode = FocusNode();
PaymentAmountProvider? _provider;
WalletsController? _wallets;
bool _isSyncingText = false;
PaymentAmountMode _mode = PaymentAmountMode.debit;
PaymentAmountFieldController({required double initialAmount})
: textController = TextEditingController(
text: amountToString(initialAmount),
);
PaymentAmountMode get mode => _mode;
bool get isReverseModeAvailable {
final sourceCurrencyCode = _sourceCurrencyCode;
return sourceCurrencyCode != null &&
sourceCurrencyCode != _settlementCurrencyCode;
}
String? get activeCurrencyCode => switch (_mode) {
PaymentAmountMode.debit => _sourceCurrencyCode,
PaymentAmountMode.settlement => _settlementCurrencyCode,
};
void update(PaymentAmountProvider provider, WalletsController wallets) {
if (!identical(_provider, provider)) {
_provider?.removeListener(_handleProviderChanged);
_provider = provider;
_provider?.addListener(_handleProviderChanged);
_syncModeWithProvider(provider);
}
if (!identical(_wallets, wallets)) {
_wallets?.removeListener(_handleWalletsChanged);
_wallets = wallets;
_wallets?.addListener(_handleWalletsChanged);
_normalizeModeForWallet();
}
_syncTextWithAmount(provider.amount);
}
void handleChanged(String value) {
if (_isSyncingText) return;
final parsed = _parseAmount(value);
if (parsed != null) {
_provider?.setAmount(parsed);
}
}
void handleModeChanged(PaymentAmountMode value) {
if (value == _mode) return;
if (!isReverseModeAvailable && value == PaymentAmountMode.settlement) {
return;
}
_mode = value;
_provider?.setSettlementMode(_settlementModeFromMode(value));
notifyListeners();
}
void _handleProviderChanged() {
final provider = _provider;
if (provider == null) return;
_syncTextWithAmount(provider.amount);
final changed = _syncModeWithProvider(provider);
if (changed) {
_normalizeModeForWallet();
notifyListeners();
}
}
void _handleWalletsChanged() {
final changed = _normalizeModeForWallet();
if (changed) {
notifyListeners();
}
}
bool _syncModeWithProvider(PaymentAmountProvider provider) {
final nextMode = _modeFromSettlementMode(provider.settlementMode);
if (nextMode == _mode) return false;
_mode = nextMode;
return true;
}
bool _normalizeModeForWallet() {
if (isReverseModeAvailable || _mode != PaymentAmountMode.settlement) {
return false;
}
_mode = PaymentAmountMode.debit;
_provider?.setSettlementMode(SettlementMode.fixSource);
return true;
}
String? get _sourceCurrencyCode {
final selectedWallet = _wallets?.selectedWallet;
if (selectedWallet == null) return null;
return currencyCodeToString(selectedWallet.currency);
}
PaymentAmountMode _modeFromSettlementMode(SettlementMode mode) =>
switch (mode) {
SettlementMode.fixReceived => PaymentAmountMode.settlement,
SettlementMode.fixSource ||
SettlementMode.unspecified => PaymentAmountMode.debit,
};
SettlementMode _settlementModeFromMode(PaymentAmountMode mode) =>
switch (mode) {
PaymentAmountMode.debit => SettlementMode.fixSource,
PaymentAmountMode.settlement => SettlementMode.fixReceived,
};
double? _parseAmount(String value) {
final parsed = parseMoneyAmount(
value.replaceAll(',', '.'),
fallback: double.nan,
);
return parsed.isNaN ? null : parsed;
}
void _syncTextWithAmount(double amount) {
final parsedText = _parseAmount(textController.text);
if (parsedText != null && parsedText == amount) return;
final nextText = amountToString(amount);
_isSyncingText = true;
textController.value = TextEditingValue(
text: nextText,
selection: TextSelection.collapsed(offset: nextText.length),
);
_isSyncingText = false;
}
@override
void dispose() {
_provider?.removeListener(_handleProviderChanged);
_wallets?.removeListener(_handleWalletsChanged);
focusNode.dispose();
textController.dispose();
super.dispose();
}
}