changed color theme to be black and added the ability to enter the amount in the recipient’s currency

This commit is contained in:
Arseni
2026-03-02 17:41:41 +03:00
parent 17e08ff26f
commit 6bb3ab5063
41 changed files with 618 additions and 239 deletions

View File

@@ -15,7 +15,7 @@ class CommonConstants {
static String clientId = '';
static String wsProto = 'ws';
static String wsEndpoint = '/ws';
static Color themeColor = Color.fromARGB(255, 80, 63, 224);
static Color themeColor = Color.fromARGB(255, 0, 0, 0);
static String nilObjectRef = '000000000000000000000000';
// Public getters for shared properties

View File

@@ -0,0 +1,20 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/money.dart';
part 'network_fee.g.dart';
@JsonSerializable()
class NetworkFeeDTO {
final MoneyDTO? networkFee;
final String? estimationContext;
const NetworkFeeDTO({
this.networkFee,
this.estimationContext,
});
factory NetworkFeeDTO.fromJson(Map<String, dynamic> json) => _$NetworkFeeDTOFromJson(json);
Map<String, dynamic> toJson() => _$NetworkFeeDTOToJson(this);
}

View File

@@ -0,0 +1,24 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/money.dart';
part 'quote_aggregate.g.dart';
@JsonSerializable()
class PaymentQuoteAggregateDTO {
final List<MoneyDTO>? debitAmounts;
final List<MoneyDTO>? expectedSettlementAmounts;
final List<MoneyDTO>? expectedFeeTotals;
final List<MoneyDTO>? networkFeeTotals;
const PaymentQuoteAggregateDTO({
this.debitAmounts,
this.expectedSettlementAmounts,
this.expectedFeeTotals,
this.networkFeeTotals,
});
factory PaymentQuoteAggregateDTO.fromJson(Map<String, dynamic> json) => _$PaymentQuoteAggregateDTOFromJson(json);
Map<String, dynamic> toJson() => _$PaymentQuoteAggregateDTOToJson(this);
}

View File

@@ -73,7 +73,7 @@ enum ResourceType {
@JsonValue('ledger_parties')
ledgerParties,
@JsonValue('ledger_posing_lines')
@JsonValue('ledger_posting_lines')
ledgerPostingLines,
@JsonValue('payments')
@@ -113,4 +113,8 @@ enum ResourceType {
/// Represents steps in workflows or processes
@JsonValue('steps')
steps,
/// Fallback for unknown values returned by backend.
@JsonValue('unknown')
unknown,
}

View File

@@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import 'package:pshared/models/payment/settlement_mode.dart';
class PaymentAmountProvider with ChangeNotifier {
double _amount = 10.0;
bool _payerCoversFee = true;
SettlementMode _settlementMode = SettlementMode.fixSource;
double get amount => _amount;
bool get payerCoversFee => _payerCoversFee;
SettlementMode get settlementMode => _settlementMode;
void setAmount(double value) {
_amount = value;
@@ -17,4 +20,10 @@ class PaymentAmountProvider with ChangeNotifier {
_payerCoversFee = value;
notifyListeners();
}
void setSettlementMode(SettlementMode value) {
if (_settlementMode == value) return;
_settlementMode = value;
notifyListeners();
}
}

View File

@@ -7,6 +7,7 @@ import 'package:pshared/provider/resource.dart';
import 'package:pshared/service/payment/multiple.dart';
import 'package:pshared/utils/exception.dart';
class MultiPaymentProvider extends ChangeNotifier {
late OrganizationsProvider _organization;
late MultiQuotationProvider _quotation;

View File

@@ -22,6 +22,8 @@ import 'package:pshared/utils/currency.dart';
import 'package:pshared/utils/payment/fx_helpers.dart';
class QuotationIntentBuilder {
static const String _settlementCurrency = 'RUB';
PaymentIntent? build({
required PaymentAmountProvider payment,
required WalletsController wallets,
@@ -39,10 +41,12 @@ class QuotationIntentBuilder {
data: paymentData,
);
final sourceCurrency = currencyCodeToString(selectedWallet.currency);
final amountCurrency = payment.settlementMode == SettlementMode.fixReceived
? _settlementCurrency
: sourceCurrency;
final amount = Money(
amount: payment.amount.toString(),
// TODO: adapt to possible other sources
currency: sourceCurrency,
currency: amountCurrency,
);
final isCryptoToCrypto =
paymentData is CryptoAddressPaymentMethod &&
@@ -50,7 +54,7 @@ class QuotationIntentBuilder {
amount.currency;
final fxIntent = FxIntentHelper.buildSellBaseBuyQuote(
baseCurrency: sourceCurrency,
quoteCurrency: 'RUB', // TODO: exentd target currencies
quoteCurrency: _settlementCurrency, // TODO: exentd target currencies
enabled: !isCryptoToCrypto,
);
return PaymentIntent(
@@ -68,7 +72,7 @@ class QuotationIntentBuilder {
feeTreatment: payment.payerCoversFee
? FeeTreatment.addToSource
: FeeTreatment.deductFromDestination,
settlementMode: SettlementMode.fixSource,
settlementMode: payment.settlementMode,
customer: customer,
);
}

View File

@@ -13,6 +13,7 @@ import 'package:pshared/models/payment/quote/quotes.dart';
import 'package:pshared/service/authorization/service.dart';
import 'package:pshared/service/services.dart';
class MultiplePaymentsService {
static final _logger = Logger('service.payment.multiple');
static const String _objectType = Services.payments;

View File

@@ -17,6 +17,7 @@ import 'package:pshared/service/authorization/storage.dart';
import 'package:pshared/service/services.dart';
import 'package:pshared/utils/http/requests.dart';
class VerificationService {
static final _logger = Logger('service.verification');
static const String _objectType = Services.verification;

View File

@@ -0,0 +1,57 @@
import 'package:pshared/models/payment/methods/card.dart';
import 'package:pshared/models/payment/methods/crypto_address.dart';
import 'package:pshared/models/payment/methods/data.dart';
import 'package:pshared/models/payment/methods/iban.dart';
import 'package:pshared/models/payment/methods/russian_bank.dart';
import 'package:pshared/models/payment/quote/quote.dart';
class PaymentQuotationCurrencyResolver {
static String? resolveQuoteCurrency({
PaymentQuote? quote,
PaymentMethodData? paymentData,
}) {
final quoteCurrency = _normalizeCurrency(
quote?.amounts?.destinationSettlement?.currency,
);
if (quoteCurrency != null) return quoteCurrency;
if (paymentData == null) return null;
final metadataCurrency = _normalizeCurrency(
paymentData.metadata?['currency'],
);
if (metadataCurrency != null) return metadataCurrency;
if (paymentData is CryptoAddressPaymentMethod) {
return _normalizeCurrency(paymentData.asset?.tokenSymbol);
}
if (paymentData is RussianBankAccountPaymentMethod ||
paymentData is CardPaymentMethod) {
return 'RUB';
}
if (paymentData is IbanPaymentMethod) {
return 'EUR';
}
return null;
}
static bool isFxEnabled({
required String? sourceCurrency,
required String? quoteCurrency,
}) {
final normalizedSource = _normalizeCurrency(sourceCurrency);
final normalizedQuote = _normalizeCurrency(quoteCurrency);
if (normalizedSource == null || normalizedQuote == null) return false;
return normalizedSource != normalizedQuote;
}
static String? _normalizeCurrency(String? value) {
final normalized = value?.trim().toUpperCase();
if (normalized == null || normalized.isEmpty) return null;
return normalized;
}
}