Skip to content

fix(asset-list): hide and use placeholders until fiat prices are available#3134

Merged
CharlVS merged 5 commits intodevfrom
bugfix/default-fiat-values
Sep 12, 2025
Merged

fix(asset-list): hide and use placeholders until fiat prices are available#3134
CharlVS merged 5 commits intodevfrom
bugfix/default-fiat-values

Conversation

@takenagain
Copy link
Copy Markdown
Contributor

@takenagain takenagain commented Sep 12, 2025

Fixes #3053 and partial solution to #3073

Desktop

image

Mobile

image

Summary by CodeRabbit

  • New Features
    • Added graceful placeholders for total balance and statistics when data is loading or unavailable.
  • Bug Fixes
    • USD balance and 24h change are hidden when data is unknown to avoid misleading zeros.
    • Disabled copy/share actions when no balance is available.
    • Improved consistency of total balance display and visibility.
  • Refactor
    • Updated header/top bar layout; consolidated language and account switchers into a single row with refined spacing.
    • Streamlined balance formatting for clearer presentation.

@takenagain takenagain added this to the v0.9.3 Release milestone Sep 12, 2025
@takenagain takenagain self-assigned this Sep 12, 2025
@takenagain takenagain added the bug Something isn't working label Sep 12, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 12, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adjusts fiat balance display to hide or defer values when data is unavailable, introduces nullable totals across wallet overview and summary, adds placeholders, and removes legacy header widgets/actions in favor of updated top bar logic. Also tweaks coin balance parentheses handling and updates StatisticCard to support null values.

Changes

Cohort / File(s) Summary of changes
Header refactor/removal and top bar updates
lib/views/common/header/app_header.dart, lib/views/common/header/actions/header_actions.dart, lib/views/main_layout/widgets/main_layout_top_bar.dart
Removed AppHeader and header actions file (language switcher, balance, account switcher). Consolidated and adjusted header logic in main layout top bar: total balance computed with nullability; conditional rendering of balance UI; minor formatting and flag map tweaks; AccountSwitcher placement adjusted.
Fiat balance text and parentheses handling
lib/shared/widgets/coin_balance.dart, lib/shared/widgets/coin_fiat_balance.dart
coin_balance: removed Row and surrounding parentheses, rendering CoinFiatBalance directly. coin_fiat_balance: now constructs balance string as " (formatted)" internally, preserving parentheses only when a value is shown.
Wallet overview and summary nullability
lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart, lib/views/wallet/wallet_page/wallet_main/balance_summary_widget.dart
totalBalance changed to nullable; UI sections render only when data exists; logging and interactions gated by data presence; BalanceSummaryWidget fields made nullable and show skeleton placeholders when null.
Expandable coin list item gating
lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart
Shows USD balance and 24h change only when lastKnownUsdBalance is non-null; otherwise hides those segments. Minor parameter reordering; explicit theme imports.
UI Kit statistic card nullability
packages/komodo_ui_kit/lib/src/display/statistic_card.dart
value made nullable and optional; renders a skeleton placeholder when value is null; minor style simplifications.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant W as WalletOverview
  participant B as CoinsBloc
  participant PG as PortfolioGrowthBloc
  participant UI as StatisticCard/BalanceSummary

  U->>W: Open Wallet
  W->>B: Get coins + USD balances
  B-->>W: List<Coin> (with usdBalance?)
  alt Any USD balance available
    W->>W: _getTotalBalance() → double
    W->>PG: Fetch 24h change (if ready)
    W->>UI: Render total balance, trend, stats
  else No USD balance available
    W->>W: _getTotalBalance() → null
    W->>UI: Render placeholders, hide trend
  end
Loading
sequenceDiagram
  autonumber
  participant L as CoinListItem
  participant C as Coin
  participant F as CoinFiatBalance

  L->>C: lastKnownUsdBalance()
  alt usdBalance != null
    L->>F: Build text " ($value)"
    F-->>L: Render fiat with parentheses
  else usdBalance == null
    L-->>L: Hide fiat segment (no brackets)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

UX, QA

Suggested reviewers

  • smk762
  • CharlVS
  • AndrewDelaney

Pre-merge checks (4 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR contains changes that appear out of scope for the stated bugfix: removal of lib/views/common/header/actions/header_actions.dart and lib/views/common/header/app_header.dart and public API/signature changes (BalanceSummaryWidget and StatisticCard made nullable/optional) are breaking or wide-ranging refactor changes not mentioned in the linked issue and thus exceed the single-issue fix. Split the refactor and API-breaking work into a separate PR (or explicitly document and justify the breaking changes), revert or clarify the header removals if they are unintended, and update all call sites/tests and changelog entries so the UI-only bugfix remains small and reviewable.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title is concise and directly describes the primary UX change — hiding fiat values and showing placeholders until fiat prices are available — and uses a conventional scope prefix; it accurately summarizes the main intent of the changeset. The "asset-list" scope is slightly narrow given the PR also affects header and shared UI components, but the title still correctly reflects the primary fix.
Linked Issues Check ✅ Passed The changes implement the core request from [#3053]: multiple components now gate rendering on null/absent fiat data and render skeleton/placeholders instead of transient "0.00" (see BalanceSummaryWidget, StatisticCard, expandable_coin_list_item, wallet_overview, and main_layout_top_bar), which prevents showing misleading zero-values; the PR uses placeholders rather than a spinner but follows the issue's recommendation to hide fiat unless a non-null/non-zero value exists.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

A hop, a skip, a balance unseen—
I wait for truth, not zeros on screen.
When data blooms, I show the shine,
Until then, placeholders align.
Ears up high, I guard the view—
Brackets hush till values are true. 🐇

✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/default-fiat-values

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 12, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Sep 12, 2025

Visit the preview URL for this PR (updated for commit ea60dc7):

https://walletrc--pull-3134-merge-mrh4796e.web.app

(expires Fri, 19 Sep 2025 14:02:43 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: f66a4ff03faa546f12f0ae5a841bd9eff2714dcc

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart (1)

180-201: Guard trend when 24h % is unavailable

If get24hChangeForAsset returns null, TrendPercentageText may receive a null percentage. Prefer hiding the row in that case to avoid crashes or misleading “0%”.

Apply:

-                  final change24hPercent = usdBalance == 0.0
-                      ? 0.0
-                      : state.get24hChangeForAsset(widget.coin.id);
+                  final change24hPercent = usdBalance == 0.0
+                      ? 0.0
+                      : state.get24hChangeForAsset(widget.coin.id);
+                  if (change24hPercent == null) {
+                    return const SizedBox.shrink();
+                  }
@@
-                  final change24hValue =
-                      change24hPercent != null && usdBalance > 0
-                      ? (change24hPercent * usdBalance / 100)
-                      : 0.0;
+                  final change24hValue = usdBalance > 0
+                      ? (change24hPercent * usdBalance / 100)
+                      : 0.0;
🧹 Nitpick comments (6)
lib/views/main_layout/widgets/main_layout_top_bar.dart (3)

68-71: Numeric type hygiene in fold

Use a double literal for the seed and for the null-coalesce to avoid inference pitfalls.

-    double total = coins.fold(
-      0,
-      (prev, coin) => prev + (coin.usdBalance(context.sdk) ?? 0),
-    );
+    final total = coins.fold<double>(
+      0.0,
+      (prev, coin) => prev + (coin.usdBalance(context.sdk) ?? 0.0),
+    );

31-41: Avoid reserving 200px when balance is hidden

Returning an empty widget keeps leading non-null, so leadingWidth: 200 still reserves space. Make leading null when totalBalance is null.

One approach: lift the BlocBuilder up to build the AppBar so you can pass leading and leadingWidth conditionally.

-        leading: BlocBuilder<CoinsBloc, CoinsState>(
-          builder: (context, state) {
-            final totalBalance = _getTotalBalance(
-              state.walletCoins.values,
-              context,
-            );
-            if (totalBalance == null) {
-              return const SizedBox.shrink();
-            }
-            return Padding(
+        leading: BlocBuilder<CoinsBloc, CoinsState>(
+          builder: (context, state) {
+            final totalBalance = _getTotalBalance(state.walletCoins.values, context);
+            if (totalBalance == null) return null;
+            return Padding(
               padding: const EdgeInsets.symmetric(horizontal: 32),
               child: ActionTextButton(
                 text: LocaleKeys.balance.tr(),
                 secondaryText: '\$${formatAmt(totalBalance)}',
                 onTap: null,
               ),
             );
           },
         ),
-        leadingWidth: 200,
+        leadingWidth: 200, // Consider setting to 0 only when leading == null

Note: You’ll need to change the AppBar creation site to allow leading: null from the builder (e.g., wrap the whole AppBar in the BlocBuilder).

Also applies to: 52-52


73-78: Clamping to $0.01 may mislead

Showing 0.01 for totals below 0.01 overstates value. Prefer '< $0.01' or show a placeholder until ≥ $0.01.

-    if (total > 0.01) {
-      return total;
-    }
-    return total != 0 ? 0.01 : 0;
+    if (total >= 0.01) return total;
+    // Return null to trigger placeholder, or use a sentinel handled by UI as '< $0.01'
+    return null;

And format in UI as: secondaryText: '< $0.01' when desired.

packages/komodo_ui_kit/lib/src/display/statistic_card.dart (1)

113-132: Remove unused stored BuildContext; avoid shadowing

The field final BuildContext context; is unused and shadows the build parameter. Simplify the widget.

-class _ValuePlaceholder extends StatelessWidget {
-  const _ValuePlaceholder({required this.context});
-
-  final BuildContext context;
+class _ValuePlaceholder extends StatelessWidget {
+  const _ValuePlaceholder({super.key});
 
   @override
   Widget build(BuildContext context) {
     return Container(
       height: 24,
       width: 120,
       decoration: BoxDecoration(
-        color: Theme.of(
-          context,
-        ).colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
+        color: Theme.of(context)
+            .colorScheme
+            .surfaceContainerHighest
+            .withOpacity(0.3), // see note below
         borderRadius: BorderRadius.circular(4),
       ),
-      child: const SizedBox.shrink(),
     );
   }
 }
lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart (2)

122-168: De-duplicate theme lookups in trend widget

Minor: cache themeCustom once to cut repeated Theme.of(...).extension calls.

-                        return TrendPercentageText(
-                          percentage: totalChange,
-                          upColor:
-                              Theme.of(context).brightness == Brightness.dark
-                              ? Theme.of(
-                                  context,
-                                ).extension<ThemeCustomDark>()!.increaseColor
-                              : Theme.of(
-                                  context,
-                                ).extension<ThemeCustomLight>()!.increaseColor,
-                          downColor:
-                              Theme.of(context).brightness == Brightness.dark
-                              ? Theme.of(
-                                  context,
-                                ).extension<ThemeCustomDark>()!.decreaseColor
-                              : Theme.of(
-                                  context,
-                                ).extension<ThemeCustomLight>()!.decreaseColor,
+                        final themeCustom = Theme.of(context).brightness == Brightness.dark
+                            ? Theme.of(context).extension<ThemeCustomDark>()!
+                            : Theme.of(context).extension<ThemeCustomLight>()!;
+                        return TrendPercentageText(
+                          percentage: totalChange,
+                          upColor: themeCustom.increaseColor,
+                          downColor: themeCustom.decreaseColor,

260-281: _getTotalBalance: single-pass + prefer lastKnownUsdBalance for consistency

  • Avoid the two passes — aggregate in one loop and use coin.lastKnownUsdBalance(context.sdk) (matches most of the codebase) instead of coin.usdBalance(...). Change in: lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart (and also lib/views/main_layout/widgets/main_layout_top_bar.dart which still uses usdBalance).
  • I couldn't find TrendPercentageText in the repo; verify its constructor nullability separately before changing call sites that depend on nullable vs non-null values.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93e94db and 4a00f55.

📒 Files selected for processing (9)
  • lib/shared/widgets/coin_balance.dart (1 hunks)
  • lib/shared/widgets/coin_fiat_balance.dart (1 hunks)
  • lib/views/common/header/actions/header_actions.dart (0 hunks)
  • lib/views/common/header/app_header.dart (0 hunks)
  • lib/views/main_layout/widgets/main_layout_top_bar.dart (5 hunks)
  • lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart (5 hunks)
  • lib/views/wallet/wallet_page/wallet_main/balance_summary_widget.dart (2 hunks)
  • lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart (6 hunks)
  • packages/komodo_ui_kit/lib/src/display/statistic_card.dart (6 hunks)
💤 Files with no reviewable changes (2)
  • lib/views/common/header/app_header.dart
  • lib/views/common/header/actions/header_actions.dart
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-04-01T15:51:37.060Z
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2566
File: lib/bloc/coins_bloc/coins_bloc.dart:10-10
Timestamp: 2025-04-01T15:51:37.060Z
Learning: In the Komodo Wallet project, part files share imports with their parent files. The import for `app_config.dart` in `coins_bloc.dart` is necessary because the part file `coins_state.dart` uses `excludedAssetList` from that package.

Applied to files:

  • lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart
  • lib/views/main_layout/widgets/main_layout_top_bar.dart
📚 Learning: 2025-04-01T15:51:37.060Z
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2566
File: lib/bloc/coins_bloc/coins_bloc.dart:10-10
Timestamp: 2025-04-01T15:51:37.060Z
Learning: The `excludedAssetList` from `app_config.dart` is used in the `_filterExcludedAssets` method in `coins_state.dart`. Since `coins_state.dart` is a part file of `coins_bloc.dart`, the import needs to be in the parent file even though it's not directly used there. In Dart, part files share the namespace and imports of their parent files.

Applied to files:

  • lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build_and_preview
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: Test web-app-macos
  • GitHub Check: unit_tests
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: validate_code_guidelines
  • GitHub Check: Build Mobile (Android)
🔇 Additional comments (10)
lib/shared/widgets/coin_balance.dart (1)

40-40: Good: parentheses now owned by CoinFiatBalance

Prevents double/bracket duplication and simplifies layout.

packages/komodo_ui_kit/lib/src/display/statistic_card.dart (2)

10-11: Null-aware value with placeholder: LGTM

The value nullable-ization and skeleton fallback are consistent with the PR goals.

Also applies to: 26-35, 76-87


124-127: Check Flutter min SDK for Color.withValues

withValues is only available on newer Flutter versions; if your min SDK is older, use withOpacity(0.3).

Would you like me to scan pubspecs to confirm the Flutter SDK constraint and replace with withOpacity if needed?

lib/views/wallet/wallet_page/wallet_main/balance_summary_widget.dart (1)

90-93: Verify ColorScheme API availability

surfaceContainerHighest.withValues(alpha: 0.3) requires recent Flutter. Use withOpacity(0.3) if you target older versions.

I can update both placeholders to withOpacity(0.3) if the current SDK doesn’t support withValues.

Also applies to: 108-111

lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart (3)

3-4: Theme extension imports: LGTM

Ensures access to increase/decrease colors for TrendPercentageText.


171-176: Hide fiat until available: LGTM

Gating the USD text on lastKnownUsdBalance prevents the transient “$0.00” flicker.


234-237: Desktop: hide trend without fiat

Good guard on null usdBalance to hide the trend row.

lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart (3)

69-73: Nullable totalBalance gate: LGTM

Returning null when no USD data exists cleanly triggers placeholders instead of “$0.00”.


74-82: Analytics value source may not match displayed value

You gate logging on totalBalance != null but log stateWithData.totalValue.value. Consider logging totalBalance for consistency with what users see, or confirm product intent.

Would you like me to update the event payload to use totalBalance?


106-113: Copy-to-clipboard gating: LGTM

Avoids copying meaningless “$0.00” when fiat is unavailable.

@takenagain takenagain force-pushed the bugfix/default-fiat-values branch from 16ef4bd to ea60dc7 Compare September 12, 2025 13:57
@takenagain takenagain added QA Ready for QA Testing UX Cosmetic or flow efficiency enhancements for improved User Experience and removed bug Something isn't working labels Sep 12, 2025
@takenagain takenagain marked this pull request as ready for review September 12, 2025 14:05
Copilot AI review requested due to automatic review settings September 12, 2025 14:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes issues with asset balance display by hiding USD balances and 24h change data when fiat prices are unavailable, and implementing placeholder skeletons during loading states. This addresses the problem of showing misleading zeros when market data isn't available.

  • Added conditional rendering to hide USD balance/change data when null
  • Implemented skeleton placeholder components for loading states
  • Refactored balance calculation methods to return null when no USD data is available

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/komodo_ui_kit/lib/src/display/statistic_card.dart Added nullable value support and skeleton placeholder widget
lib/views/wallet/wallet_page/wallet_main/wallet_overview.dart Updated total balance calculation to return null when no USD data available
lib/views/wallet/wallet_page/wallet_main/balance_summary_widget.dart Added placeholder widgets and nullable balance support
lib/views/wallet/wallet_page/common/expandable_coin_list_item.dart Added null checks to hide USD balance when unavailable
lib/views/main_layout/widgets/main_layout_top_bar.dart Updated balance display logic with null handling
lib/views/common/header/app_header.dart Removed entire file (legacy header component)
lib/views/common/header/actions/header_actions.dart Removed entire file (legacy header actions)
lib/shared/widgets/coin_fiat_balance.dart Added null check for USD balance display
lib/shared/widgets/coin_balance.dart Simplified balance display structure

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

}

final formattedBalance = formatUsdValue(usdBalance);
final balanceStr = ' ($formattedBalance)';
Copy link

Copilot AI Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable balanceStr is defined but never used. The parentheses formatting that was previously applied to the balance display has been moved into this unused variable, but the actual widget construction on line 48 uses formattedBalance directly.

Copilot uses AI. Check for mistakes.
@CharlVS CharlVS linked an issue Sep 12, 2025 that may be closed by this pull request
@CharlVS CharlVS merged commit 043e8d3 into dev Sep 12, 2025
9 of 14 checks passed
@CharlVS CharlVS deleted the bugfix/default-fiat-values branch September 12, 2025 14:19
@CharlVS CharlVS mentioned this pull request Oct 5, 2025
@smk762 smk762 mentioned this pull request Nov 23, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA Ready for QA Testing UX Cosmetic or flow efficiency enhancements for improved User Experience

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suboptimal fiat display where data not available

3 participants