Merge remote-tracking branch 'origin/send-wallet-core' into brightness-fix
What changed, and why it matters
This commit is a routine merge that moves fiat-currency handling into a shared library and adds a 'switch amount unit' feature on the send screen. There is no security-relevant change visible in the diff.
No security action required. Review the AmountEntryController implementation in the wallet_fiat package if you want to confirm input-sanitization behavior, but the diff itself is a refactor/feature merge.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The merge resolves conflicts across localization files and several UI screens. It removes hard-coded fiat currency lists/symbols from the app and instead imports them from the wallet_fiat package (FiatCurrency, FiatQuote). The send screen replaces a raw TextEditingController with an AmountEntryController that can toggle between XMR and fiat input, and updates validation/fee calculation to read the coin-denominated value. No cryptographic, authentication, network, or permission changes are present.
Changed components
lib/screens/send.dartlib/screens/wallet_home.dartlib/screens/fiat_api_setup_screen.dartlib/screens/desktop/fiat_setup_view.dartlib/widgets/fiat_api_settings_form.dartlib/models/fiat_rate_model.dartlib/consts.dartlocalization filesInspect captured patch +77 / −105
### lib/consts.dart
@@ -3,15 +3,4 @@ const String torDataDirName = 'tor';
const int txDirectionIncoming = 0;
const int txDirectionOutgoing = 1;
const int moneroDecimals = 12;
-const supportedFiatCurrencies = ['USD', 'EUR', 'CAD', 'AUD', 'GBP', 'CHF', 'JPY'];
-const indirectPairCurrencies = ['CAD', 'AUD', 'GBP', 'CHF', 'JPY'];
-const currencySymbols = {
- 'USD': '\$',
- 'EUR': '€',
- 'CAD': 'C\$',
- 'AUD': 'A\$',
- 'GBP': '£',
- 'CHF': 'Fr',
- 'JPY': '¥',
-};
const walletPasswordStorageKey = 'walletPassword';
### lib/l10n/app_en.arb
@@ -315,6 +315,7 @@
"sendPickContactTitle": "Send to a contact",
"sendAvailableSuffix": "available",
"sendIrreversibleNote": "Monero transactions are irreversible. Double-check the address and amount before sending.",
+ "sendSwitchUnit": "Switch amount unit",
"sendFailedToGetFeesError": "Failed to get fees.",
"torSettingsTitle": "Tor Settings",
"torSettingsModeBuiltIn": "Built-in Tor",
### lib/l10n/app_localizations.dart
@@ -1731,6 +1731,12 @@ abstract class AppLocalizations {
/// **'Monero transactions are irreversible. Double-check the address and amount before sending.'**
String get sendIrreversibleNote;
+ /// No description provided for @sendSwitchUnit.
+ ///
+ /// In en, this message translates to:
+ /// **'Switch amount unit'**
+ String get sendSwitchUnit;
+
/// No description provided for @sendFailedToGetFeesError.
///
/// In en, this message translates to:
### lib/l10n/app_localizations_en.dart
@@ -882,6 +882,9 @@ class AppLocalizationsEn extends AppLocalizations {
String get sendIrreversibleNote =>
'Monero transactions are irreversible. Double-check the address and amount before sending.';
+ @override
+ String get sendSwitchUnit => 'Switch amount unit';
+
@override
String get sendFailedToGetFeesError => 'Failed to get fees.';
### lib/l10n/app_localizations_pt.dart
@@ -883,6 +883,9 @@ class AppLocalizationsPt extends AppLocalizations {
String get sendIrreversibleNote =>
'Transações Monero são irreversíveis. Confira o endereço e o valor antes de enviar.';
+ @override
+ String get sendSwitchUnit => 'Alternar unidade do valor';
+
@override
String get sendFailedToGetFeesError => 'Não foi possível carregar taxas.';
### lib/l10n/app_pt.arb
@@ -315,6 +315,7 @@
"sendPickContactTitle": "Enviar para um contato",
"sendAvailableSuffix": "disponível",
"sendIrreversibleNote": "Transações Monero são irreversíveis. Confira o endereço e o valor antes de enviar.",
+ "sendSwitchUnit": "Alternar unidade do valor",
"sendFailedToGetFeesError": "Não foi possível carregar taxas.",
"torSettingsTitle": "Configurações do Tor",
"torSettingsModeBuiltIn": "Tor Integrado",
### lib/models/fiat_rate_model.dart
@@ -3,4 +3,4 @@
// sites are unchanged; the app supplies the Tor proxy via FiatRates.install and
// attaches the WalletManager via attachFiatWalletManager in wallet_core_glue.dart.
// The fiatAutoDisabledByTor auto-disable/restore stays app-side (tor_settings_form).
-export 'package:wallet_fiat/wallet_fiat.dart' show FiatRateModel, FiatApiMode;
+export 'package:wallet_fiat/wallet_fiat.dart' show FiatRateModel, FiatApiMode, FiatCurrency, FiatQuote;
### lib/screens/desktop/fiat_setup_view.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:wallet_fiat/wallet_fiat.dart';
import 'package:skylight_wallet/widgets/ui/ui.dart';
@@ -9,7 +10,7 @@ class DesktopFiatSetupView extends StatelessWidget {
final FiatSetupLabels labels;
final String noteRatesOnly;
final String noteTor;
- final List<FiatCurrencyOption> currencies;
+ final List<FiatCurrency> currencies;
final int modeIndex;
final String currency;
final bool offerTorOnly;
@@ -23,7 +24,7 @@ class DesktopFiatSetupView extends StatelessWidget {
required this.labels,
required this.noteRatesOnly,
required this.noteTor,
- required this.currencies,
+ this.currencies = FiatCurrency.all,
required this.modeIndex,
required this.currency,
required this.offerTorOnly,
### lib/screens/fiat_api_setup_screen.dart
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:skylight_wallet/consts.dart';
import 'package:skylight_wallet/l10n/app_localizations.dart';
import 'package:skylight_wallet/models/fiat_rate_model.dart';
import 'package:skylight_wallet/screens/desktop/fiat_setup_view.dart';
@@ -56,17 +55,12 @@ class _FiatApiSetupScreenState extends State<FiatApiSetupScreen> {
currencyLabel: i18n.fiatApiSettingsDisplayCurrencyLabel,
continueText: i18n.lwsSetupContinueButton,
);
- final currencies = [
- for (final code in supportedFiatCurrencies)
- FiatCurrencyOption(code: code, symbol: currencySymbols[code] ?? ''),
- ];
if (isDesktop) {
return DesktopFiatSetupView(
labels: labels,
noteRatesOnly: i18n.onboardingPriceNoteRatesOnly,
noteTor: i18n.onboardingPriceNoteTor,
- currencies: currencies,
modeIndex: _fiatMode.index,
currency: _fiatCurrency,
offerTorOnly: !_globalTorDisabled,
@@ -79,7 +73,6 @@ class _FiatApiSetupScreenState extends State<FiatApiSetupScreen> {
return FiatSetupView(
labels: labels,
- currencies: currencies,
modeIndex: _fiatMode.index,
currency: _fiatCurrency,
offerTorOnly: !_globalTorDisabled,
### lib/screens/send.dart
@@ -7,7 +7,6 @@ import 'package:provider/provider.dart';
import 'package:wallet_domain/wallet_domain.dart' show baseUnitsToDecimalString, decimalToBaseUnits;
import 'package:wallet_infra/wallet_infra.dart' show StoreReview;
-import 'package:skylight_wallet/consts.dart' as consts;
import 'package:skylight_wallet/l10n/app_localizations.dart';
import 'package:skylight_wallet/models/app_wallet.dart';
import 'package:skylight_wallet/models/contact_model.dart';
@@ -64,7 +63,9 @@ class _SendScreenState extends State<SendScreen> {
bool _isLoading = false;
bool _isLoadingFees = false;
final _destinationAddressController = TextEditingController(text: '');
- final _amountController = TextEditingController(text: '');
+ /// The amount, typed in XMR or fiat. Read what is spent from
+ /// `_amount.baseUnits` / `_amount.coinText`, never from its field.
+ late final AmountEntryController _amount;
bool _isSweepAll = false;
Contact? _selectedContact;
List<int?>? _fees; // estimated fee (piconero) per priority; null = estimate failed
@@ -89,9 +90,9 @@ class _SendScreenState extends State<SendScreen> {
@override
void dispose() {
_destinationAddressController.removeListener(_onAddressChanged);
- _amountController.removeListener(_onAmountChanged);
+ _amount.removeListener(_onAmountChanged);
_destinationAddressController.dispose();
- _amountController.dispose();
+ _amount.dispose();
super.dispose();
}
@@ -105,9 +106,14 @@ class _SendScreenState extends State<SendScreen> {
if (_didInit) return;
_didInit = true;
+ _amount = AmountEntryController(
+ quotes: Provider.of<FiatRateModel>(context, listen: false),
+ coinSymbol: 'XMR',
+ coinDecimals: _xmrDecimals,
+ );
_loadFormFromArgs();
_destinationAddressController.addListener(_onAddressChanged);
- _amountController.addListener(_onAmountChanged);
+ _amount.addListener(_onAmountChanged);
// Validate any prefilled values (contact/QR args) so the button reflects them.
_revalidate();
}
@@ -117,7 +123,8 @@ class _SendScreenState extends State<SendScreen> {
if (args != null) {
_destinationAddressController.text = args.destinationAddress;
- _amountController.text = args.amount ?? '';
+ final amount = args.amount;
+ if (amount != null && amount.isNotEmpty) _amount.setCoinText(amount);
// Same field the in-send picker sets, so the contact card renders here too.
_selectedContact = args.contact;
}
@@ -165,7 +172,8 @@ class _SendScreenState extends State<SendScreen> {
_destinationAddressController.text = address;
if (amount != null) {
- _amountController.text = _asExactAmount(amount);
+ // A payment request is denominated in XMR, so entry switches to XMR.
+ _amount.setCoinText(_asExactAmount(amount));
}
}
@@ -290,10 +298,9 @@ class _SendScreenState extends State<SendScreen> {
}
Future<bool> _validateForm({bool setErrors = true}) async {
- final amount = double.tryParse(_amountController.text) ?? 0;
final unresolvedDestinationAddress = _destinationAddressController.text;
- if (amount == 0) {
+ if (_amount.baseUnits == BigInt.zero) {
return false;
}
@@ -320,7 +327,7 @@ class _SendScreenState extends State<SendScreen> {
return false;
}
- if (_amountUnits() > (wallet.unlockedBalanceBaseUnits ?? BigInt.zero)) {
+ if (_amount.baseUnits > (wallet.unlockedBalanceBaseUnits ?? BigInt.zero)) {
if (setErrors) {
setState(() {
_amountError = i18n.sendInsufficientBalanceError;
@@ -333,7 +340,7 @@ class _SendScreenState extends State<SendScreen> {
}
Future<void> _calculateFees() async {
- final feeFetchKey = '${_destinationAddressController.text}-${_amountController.text}';
+ final feeFetchKey = '${_destinationAddressController.text}-${_amount.coinText}';
if (feeFetchKey == _lastFeeFetchKey) {
return;
@@ -354,7 +361,7 @@ class _SendScreenState extends State<SendScreen> {
});
final destinationAddress = await _resolveDestinationAddress();
- final amountText = _amountController.text;
+ final amountText = _amount.coinText;
try {
// Estimate the fee per priority natively (no full tx build).
@@ -449,7 +456,7 @@ class _SendScreenState extends State<SendScreen> {
// screen are estimates, not tx objects, so always construct here).
final tx = await wallet.createTx(
destinationAddress,
- _amountController.text,
+ _amount.coinText,
_isSweepAll,
priority: _selectedPriority + 1,
);
@@ -470,7 +477,7 @@ class _SendScreenState extends State<SendScreen> {
if (error.toString().contains('Unlocked funds too low')) {
// Display-only: picks which of two error messages to show, so the
// imprecision of a double cannot reach an amount anyone spends.
- final approxAmount = double.tryParse(_amountController.text) ?? 0;
+ final approxAmount = double.tryParse(_amount.coinText) ?? 0;
if (wallet.unlockedBalance! > approxAmount) {
setState(() {
_amountError = i18n.sendInsufficientBalanceToCoverFeeError;
@@ -502,11 +509,9 @@ class _SendScreenState extends State<SendScreen> {
String? destinationOpenAliasName,
}) async {
final i18n = AppLocalizations.of(context)!;
- final fiatRate = Provider.of<FiatRateModel>(context, listen: false);
- final fiatSymbol = fiatRate.fiatCode == 'EUR' ? '€' : '\$';
- final xmrRate = fiatRate.rateFor('XMR');
- final amountFiat = xmrRate is double ? tx.amount * xmrRate : null;
- final feeFiat = xmrRate is double ? tx.fee * xmrRate : null;
+ final quote = Provider.of<FiatRateModel>(context, listen: false).quoteFor('XMR');
+ final amountFiat = quote != null ? tx.amount * quote.rate : null;
+ final feeFiat = quote != null ? tx.fee * quote.rate : null;
// Monero fee is same-currency, so compare directly. Warn when it's ≥10% of
// the amount (mirrors Spice's confirm-send high-fee guard).
@@ -526,9 +531,9 @@ class _SendScreenState extends State<SendScreen> {
),
coinSymbol: 'XMR',
amountText: '${tx.amount.toStringAsFixed(12)} XMR',
- amountFiat: amountFiat != null ? formatFiat(amountFiat, fiatSymbol) : null,
+ amountFiat: amountFiat != null ? formatFiat(amountFiat, quote!.currency) : null,
feeText: '${tx.fee.toStringAsFixed(12)} XMR',
- feeFiat: feeFiat != null ? formatFiat(feeFiat, fiatSymbol) : null,
+ feeFiat: feeFiat != null ? formatFiat(feeFiat, quote!.currency) : null,
address: destinationAddress,
openAlias: destinationOpenAlias,
openAliasName: destinationOpenAliasName,
@@ -582,7 +587,11 @@ class _SendScreenState extends State<SendScreen> {
// intact. Sweep-all normally makes the amount moot, but editing the field
// clears that flag and the number becomes the real amount.
final units = wallet.unlockedBalanceBaseUnits;
- _amountController.text = units == null ? '' : baseUnitsToDecimalString(units, _xmrDecimals);
+ if (units == null) {
+ _amount.clear();
+ } else {
+ _amount.setMax(units);
+ }
setState(() {
_isSweepAll = true;
@@ -611,20 +620,11 @@ class _SendScreenState extends State<SendScreen> {
await _revalidate();
}
- /// The typed amount in piconero, or zero when the field is not a number.
- BigInt _amountUnits() {
- try {
- return decimalToBaseUnits(_amountController.text, _xmrDecimals);
- } on FormatException {
- return BigInt.zero;
- }
- }
-
Future<void> _onAmountChanged() async {
final wallet = appWalletOf(context);
// Base units for the same reason as in `_validateForm`: `==` between two
// differently-rounded doubles decided whether this is a sweep.
- final isFullBalance = _amountUnits() == wallet.unlockedBalanceBaseUnits;
+ final isFullBalance = _amount.baseUnits == wallet.unlockedBalanceBaseUnits;
if (isFullBalance && !_isSweepAll) {
setState(() {
@@ -648,19 +648,14 @@ class _SendScreenState extends State<SendScreen> {
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context)!;
final wallet = appWalletOf(context, listen: true);
- final fiatRate = context.watch<FiatRateModel>();
- final fiatSymbol = consts.currencySymbols[fiatRate.fiatCode] ?? '\$';
- final coinRate = fiatRate.rateFor('XMR');
-
- final amount = double.tryParse(_amountController.text) ?? 0;
- final amountFiat = coinRate != null ? amount * coinRate : 0.0;
+ final quote = context.watch<FiatRateModel>().quoteFor('XMR');
final available = wallet.unlockedBalance ?? 0;
final xmr = xmrWallet(context);
if (isDesktop) {
return DesktopShell(
active: DesktopNav.home,
- child: _desktopBody(context, i18n, fiatSymbol, coinRate, amountFiat, available),
+ child: _desktopBody(context, i18n, quote, available),
);
}
@@ -679,6 +674,7 @@ class _SendScreenState extends State<SendScreen> {
maxButton: i18n.sendMaxButton,
addressHint: i18n.address,
priorityLabels: [i18n.sendPriorityLow, i18n.sendPriorityNormal, i18n.sendPriorityHigh],
+ switchUnit: i18n.sendSwitchUnit,
),
onBack: () => Navigator.of(context).pop(),
addressController: _destinationAddressController,
@@ -692,19 +688,17 @@ class _SendScreenState extends State<SendScreen> {
? _shortenMiddle(_destinationAddressController.text, head: 8, tail: 10)
: null,
onClearContact: _clearSelectedContact,
- amountController: _amountController,
+ amount: _amount,
amountError: _amountError,
onMax: _setBalanceAsSendAmount,
- coinSymbol: 'XMR',
- amountFiatText: '≈ ${formatFiat(amountFiat, fiatSymbol)}',
availableText: '${_amountText(available)} ${i18n.sendAvailableSuffix}',
availableLeading: xmr != null
? CoinMark(coinSymbol: xmr.coinSymbol, iconAsset: xmr.iconAsset, size: 16)
: const SizedBox(width: 16, height: 16),
onAvailableTap: _setBalanceAsSendAmount,
selectedPriority: _selectedPriority,
onSelectPriority: _setPriority,
- feeValue: _feeValue(fiatSymbol, coinRate),
+ feeValue: _feeValue(quote),
onCancel: () => Navigator.pop(context),
onSend: (_formValid && _openAliasResolving == 0 && !_isLoading) ? _send : null,
sendLoading: _isLoading,
@@ -716,9 +710,7 @@ class _SendScreenState extends State<SendScreen> {
Widget _desktopBody(
BuildContext context,
AppLocalizations i18n,
- String fiatSymbol,
- double? coinRate,
- double amountFiat,
+ FiatQuote? quote,
double available,
) {
final canSend = _formValid && _openAliasResolving == 0 && !_isLoading;
@@ -729,17 +721,15 @@ class _SendScreenState extends State<SendScreen> {
const SizedBox(height: 16),
Text(i18n.sendTitle, style: desktopTitleStyle),
const SizedBox(height: 24),
- _sendForm(context, i18n, fiatSymbol, coinRate, amountFiat, available, canSend),
+ _sendForm(context, i18n, quote, available, canSend),
],
);
}
Widget _sendForm(
BuildContext context,
AppLocalizations i18n,
- String fiatSymbol,
- double? coinRate,
- double amountFiat,
+ FiatQuote? quote,
double available,
bool canSend,
) {
@@ -749,7 +739,7 @@ class _SendScreenState extends State<SendScreen> {
_dField(i18n.sendToLabel, _dToCard(i18n)),
if (_destinationAddressError.isNotEmpty) _dError(_destinationAddressError),
const SizedBox(height: 16),
- _dField(i18n.amount, _dAmountCard(i18n, fiatSymbol, amountFiat, available)),
+ _dField(i18n.amount, _dAmountCard(i18n, quote, available)),
if (_amountError.isNotEmpty) _dError(_amountError),
],
);
@@ -778,7 +768,7 @@ class _SendScreenState extends State<SendScreen> {
color: BrandColors.inkMuted,
),
),
- _feeValue(fiatSymbol, coinRate),
+ _feeValue(quote),
],
),
],
@@ -927,8 +917,7 @@ class _SendScreenState extends State<SendScreen> {
Widget _dAmountCard(
AppLocalizations i18n,
- String fiatSymbol,
- double amountFiat,
+ FiatQuote? quote,
double available,
) {
return _dCard(
@@ -939,7 +928,7 @@ class _SendScreenState extends State<SendScreen> {
children: [
Expanded(
child: TextField(
- controller: _amountController,
+ controller: _amount.field,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
style: TextStyle(
fontFamily: 'Ubuntu Mono',
@@ -999,14 +988,17 @@ class _SendScreenState extends State<SendScreen> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Text(
- '≈ ${formatFiat(amountFiat, fiatSymbol)}',
- style: TextStyle(
- fontFamily: 'Ubuntu Mono',
- fontSize: 12.5,
- color: BrandColors.inkMuted,
- ),
- ),
+ if (quote != null)
+ Text(
+ '≈ ${formatFiat((double.tryParse(_amount.coinText) ?? 0) * quote.rate, quote.currency)}',
+ style: TextStyle(
+ fontFamily: 'Ubuntu Mono',
+ fontSize: 12.5,
+ color: BrandColors.inkMuted,
+ ),
+ )
+ else
+ const SizedBox.shrink(),
Text(
'${_amountText(available)} ${i18n.sendAvailableSuffix}',
style: TextStyle(
@@ -1052,7 +1044,7 @@ class _SendScreenState extends State<SendScreen> {
),
);
- Widget _feeValue(String fiatSymbol, double? coinRate) {
+ Widget _feeValue(FiatQuote? quote) {
final feePiconero = (_fees != null && _fees!.length > _selectedPriority)
? _fees![_selectedPriority]
: null;
@@ -1070,7 +1062,7 @@ class _SendScreenState extends State<SendScreen> {
);
}
final fee = doubleAmountFromInt(feePiconero);
- final feeFiat = coinRate != null ? ' · ${formatFiat(fee * coinRate, fiatSymbol)}' : '';
+ final feeFiat = quote != null ? ' · ${formatFiat(fee * quote.rate, quote.currency)}' : '';
return Row(
mainAxisSize: MainAxisSize.min,
children: [
### lib/screens/wallet_home.dart
@@ -6,7 +6,6 @@ import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:skeletonizer/skeletonizer.dart';
-import 'package:skylight_wallet/consts.dart' as consts;
import 'package:skylight_wallet/l10n/app_localizations.dart';
import 'package:skylight_wallet/models/app_wallet.dart';
import 'package:skylight_wallet/models/fiat_rate_model.dart';
@@ -45,7 +44,6 @@ typedef _HomeValues = ({
double unlockedBalance,
double? unlockedBalanceFiat,
double lockedBalance,
- String fiatSymbol,
StatusIconStatus status,
bool disconnected,
});
@@ -56,7 +54,6 @@ _HomeValues _deriveHome(AppWallet wallet, FiatRateModel fiatRate) {
? wallet.unlockedBalance! * fiatRate.rateFor('XMR')!
: null;
final lockedBalance = (wallet.totalBalance ?? 0) - (wallet.unlockedBalance ?? 0);
- final fiatSymbol = consts.currencySymbols[fiatRate.fiatCode] ?? '\$';
var status = StatusIconStatus.fail;
if (wallet.isFullySynced) {
@@ -73,7 +70,6 @@ _HomeValues _deriveHome(AppWallet wallet, FiatRateModel fiatRate) {
unlockedBalance: unlockedBalance,
unlockedBalanceFiat: unlockedBalanceFiat,
lockedBalance: lockedBalance,
- fiatSymbol: fiatSymbol,
status: status,
disconnected: wallet.torRequirementBroken || status == StatusIconStatus.fail,
);
@@ -156,7 +152,6 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
unlockedBalance: v.unlockedBalance,
unlockedBalanceFiat: v.unlockedBalanceFiat,
lockedBalance: v.lockedBalance,
- fiatSymbol: v.fiatSymbol,
fiatRate: fiatRate,
disconnected: v.disconnected,
),
@@ -181,7 +176,6 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
wallet: wallet,
i18n: i18n,
fiatRate: fiatRate,
- fiatSymbol: v.fiatSymbol,
onTapTx: _showTxDetails,
),
const SliverToBoxAdapter(child: SizedBox(height: 24)),
@@ -231,7 +225,6 @@ class _BalanceHero extends StatelessWidget {
final double unlockedBalance;
final double? unlockedBalanceFiat;
final double lockedBalance;
- final String fiatSymbol;
final FiatRateModel fiatRate;
final bool disconnected;
@@ -240,7 +233,6 @@ class _BalanceHero extends StatelessWidget {
required this.unlockedBalance,
required this.unlockedBalanceFiat,
required this.lockedBalance,
- required this.fiatSymbol,
required this.fiatRate,
required this.disconnected,
});
@@ -259,7 +251,7 @@ class _BalanceHero extends StatelessWidget {
// Fiat leads when available; otherwise the coin amount is the hero,
// with a skeleton while the rate is still loading.
if (showFiat)
- BalanceText.split(formatFiat(unlockedBalanceFiat!, fiatSymbol), style: _balanceStyle)
+ BalanceText.split(formatFiat(unlockedBalanceFiat!, fiatRate.fiatCurrency), style: _balanceStyle)
else if (!fiatRate.isDisabled && !fiatRate.hasFailed)
Skeletonizer(child: Text('0.0000', style: _balanceStyle))
else
@@ -380,15 +372,13 @@ class _ActivitySliver extends StatelessWidget {
final AppWallet wallet;
final AppLocalizations i18n;
final FiatRateModel fiatRate;
- final String fiatSymbol;
final double horizontalPadding;
final void Function(TxDetails tx) onTapTx;
const _ActivitySliver({
required this.wallet,
required this.i18n,
required this.fiatRate,
- required this.fiatSymbol,
required this.onTapTx,
this.horizontalPadding = 20,
});
@@ -449,7 +439,6 @@ class _ActivitySliver extends StatelessWidget {
showCoinIcon: false,
labels: TxActivityLabels(received: i18n.coinHomeReceived, sent: i18n.coinHomeSent),
fiatRate: fiatRate,
- fiatSymbol: fiatSymbol,
showDivider: next is TxDetails,
onTap: () => onTapTx(tx),
);
@@ -517,7 +506,7 @@ class DesktopHomeView extends StatelessWidget {
children: [
if (showFiat)
BalanceText.split(
- formatFiat(v.unlockedBalanceFiat!, v.fiatSymbol),
+ formatFiat(v.unlockedBalanceFiat!, fiatRate.fiatCurrency),
style: _bigBalance,
)
else if (!fiatRate.isDisabled && !fiatRate.hasFailed)
@@ -576,7 +565,6 @@ class DesktopHomeView extends StatelessWidget {
wallet: wallet,
i18n: i18n,
fiatRate: fiatRate,
- fiatSymbol: v.fiatSymbol,
horizontalPadding: 44,
onTapTx: (tx) => showTxDetailsDialog(context, tx),
),
### lib/widgets/fiat_api_settings_form.dart
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:skylight_wallet/consts.dart';
import 'package:skylight_wallet/l10n/app_localizations.dart';
import 'package:skylight_wallet/models/fiat_rate_model.dart';
import 'package:skylight_wallet/services/shared_preferences_service.dart';
@@ -79,10 +78,6 @@ class _FiatApiSettingsFormState extends State<FiatApiSettingsForm> {
modeIndex: _mode.index,
onModeChanged: (i) => setState(() => _mode = FiatApiMode.values[i]),
currencyLabel: i18n.fiatApiSettingsDisplayCurrencyLabel,
- currencies: [
- for (final code in supportedFiatCurrencies)
- FiatCurrencyOption(code: code, symbol: currencySymbols[code] ?? ''),
- ],
currency: _currency,
onCurrencyChanged: (c) => setState(() => _currency = c),
),Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.