Show fiat API failure as a warning triangle by the balance; aligns with Spice
What changed, and why it matters
This commit is a cosmetic user-interface change. It swaps a text-based fiat exchange-rate error message for a warning-triangle icon with a tooltip and shows the coin balance more clearly when the fiat rate is unavailable. There is no security-relevant behavior change.
No security action needed; this is a normal UI/UX polish change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies lib/screens/wallet_home.dart to change how a failed fiat API rate is presented. Previously a full inline error caption was rendered; now the fiat hero shows ‘–’ with a warning icon tooltip and the coin amount remains visible as the sub-line. No logic for fetching, trusting, or acting on the rate is altered.
Changed components
lib/screens/wallet_home.dartInspect captured patch +64 / −54
### lib/screens/wallet_home.dart
@@ -250,17 +250,38 @@ class _BalanceHero extends StatelessWidget {
children: [
// 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!, fiatRate.fiatCurrency),
- style: _balanceStyle,
- )
- else if (!fiatRate.isDisabled && !fiatRate.hasFailed)
- Skeletonizer(child: Text('0.0000', style: _balanceStyle))
- else
- Text(coinText, style: _balanceStyle),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Flexible(
+ child: showFiat
+ ? BalanceText.split(
+ formatFiat(unlockedBalanceFiat!, fiatRate.fiatCurrency),
+ style: _balanceStyle,
+ )
+ : (!fiatRate.isDisabled && !fiatRate.hasFailed)
+ ? Skeletonizer(child: Text('0.0000', style: _balanceStyle))
+ : (fiatRate.hasFailed && !fiatRate.isDisabled)
+ ? Text('--', style: _balanceStyle)
+ : Text(coinText, style: _balanceStyle),
+ ),
+ if (fiatRate.hasFailed && !fiatRate.isDisabled) ...[
+ const SizedBox(width: 8),
+ Padding(
+ padding: const EdgeInsets.only(top: 6),
+ child: Tooltip(
+ message: i18n.homeFiatApiError,
+ child: Icon(Icons.warning_rounded, size: 18, color: BrandColors.warning),
+ ),
+ ),
+ ],
+ ],
+ ),
const SizedBox(height: 10),
- if (showFiat) Text(coinText, style: _balanceSubStyle),
+ // When the rate is unavailable the fiat hero is '--', so keep the coin
+ // amount visible as the sub-line.
+ if (showFiat || (fiatRate.hasFailed && !fiatRate.isDisabled))
+ Text(coinText, style: _balanceSubStyle),
// Funds that have arrived but aren't spendable yet — Monero locks a
// receipt for ten blocks, so the unlocked balance above omits it.
if (lockedBalance > 0)
@@ -271,23 +292,6 @@ class _BalanceHero extends StatelessWidget {
style: _balanceSubStyle,
),
),
- if (fiatRate.hasFailed && !fiatRate.isDisabled)
- Padding(
- padding: const EdgeInsets.only(top: 6),
- child: Row(
- children: [
- Icon(Icons.warning_rounded, size: 15, color: BrandColors.error),
- const SizedBox(width: 6),
- Flexible(
- child: Text(
- i18n.homeFiatApiError,
- overflow: TextOverflow.ellipsis,
- style: BrandText.caption.copyWith(color: BrandColors.error),
- ),
- ),
- ],
- ),
- ),
_ConnectionRow(wallet: wallet, disconnected: disconnected),
],
),
@@ -507,17 +511,40 @@ class DesktopHomeView extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- if (showFiat)
- BalanceText.split(
- formatFiat(v.unlockedBalanceFiat!, fiatRate.fiatCurrency),
- style: _bigBalance,
- )
- else if (!fiatRate.isDisabled && !fiatRate.hasFailed)
- Skeletonizer(child: Text('0.0000', style: _bigBalance))
- else
- Text(coinText, style: _bigBalance),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Flexible(
+ child: showFiat
+ ? BalanceText.split(
+ formatFiat(v.unlockedBalanceFiat!, fiatRate.fiatCurrency),
+ style: _bigBalance,
+ )
+ : (!fiatRate.isDisabled && !fiatRate.hasFailed)
+ ? Skeletonizer(child: Text('0.0000', style: _bigBalance))
+ : (fiatRate.hasFailed && !fiatRate.isDisabled)
+ ? Text('--', style: _bigBalance)
+ : Text(coinText, style: _bigBalance),
+ ),
+ if (fiatRate.hasFailed && !fiatRate.isDisabled) ...[
+ const SizedBox(width: 8),
+ Padding(
+ padding: const EdgeInsets.only(top: 6),
+ child: Tooltip(
+ message: i18n.homeFiatApiError,
+ child: Icon(
+ Icons.warning_rounded,
+ size: 18,
+ color: BrandColors.warning,
+ ),
+ ),
+ ),
+ ],
+ ],
+ ),
const SizedBox(height: 12),
- if (showFiat) Text(coinText, style: _balanceSubStyle),
+ if (showFiat || (fiatRate.hasFailed && !fiatRate.isDisabled))
+ Text(coinText, style: _balanceSubStyle),
if (v.lockedBalance > 0)
Padding(
padding: const EdgeInsets.only(top: 6),
@@ -526,23 +553,6 @@ class DesktopHomeView extends StatelessWidget {
style: _balanceSubStyle,
),
),
- if (fiatRate.hasFailed && !fiatRate.isDisabled)
- Padding(
- padding: const EdgeInsets.only(top: 6),
- child: Row(
- children: [
- Icon(Icons.warning_rounded, size: 15, color: BrandColors.error),
- const SizedBox(width: 6),
- Flexible(
- child: Text(
- i18n.homeFiatApiError,
- overflow: TextOverflow.ellipsis,
- style: BrandText.caption.copyWith(color: BrandColors.error),
- ),
- ),
- ],
- ),
- ),
if (configured) ...[
const SizedBox(height: 14),
ConnectionPills(wallet: cw),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.