Skip to content

fix(nft): add IPFS gateway resolution, retry, and fallback to improve NFT image loading#3020

Merged
CharlVS merged 21 commits intodevfrom
bugfix/nft-image-loading
Aug 6, 2025
Merged

fix(nft): add IPFS gateway resolution, retry, and fallback to improve NFT image loading#3020
CharlVS merged 21 commits intodevfrom
bugfix/nft-image-loading

Conversation

@takenagain
Copy link
Copy Markdown
Contributor

@takenagain takenagain commented Jul 29, 2025

Summary by CodeRabbit

  • New Features

    • Introduced robust NFT image and video loading with automatic fallback across multiple URLs and gateways, improving reliability for IPFS-hosted media.
    • Enhanced media type detection for images, SVGs, GIFs, and videos.
    • Added in-memory tracking of failing IPFS gateways to avoid repeated failed requests.
    • Centralized IPFS gateway configuration for platform-specific optimization.
  • Refactor

    • Refactored NFT image and video widgets to use a reactive Bloc-based approach for better error handling and fallback support.
    • Updated parameter names for NFT image widgets to ensure consistency.
  • Bug Fixes

    • Corrected constructor parameter names for NFT image widgets across multiple views to ensure proper image loading.
  • Tests

    • Added comprehensive unit tests for IPFS gateway management and fallback logic.

@takenagain takenagain self-assigned this Jul 29, 2025
@takenagain takenagain added the bug Something isn't working label Jul 29, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jul 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

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

This update introduces a robust IPFS gateway management and fallback mechanism for NFT image and video loading. It adds a new IpfsGatewayManager utility, integrates a Bloc-based fallback loader for NFT media, centralizes gateway constants, and updates all usages to support the new system. Comprehensive unit tests for the gateway manager are included.

Changes

Cohort / File(s) Change Summary
Bloc Integration for NFT Image Fallback
lib/bloc/nft_image/nft_image_bloc.dart, lib/bloc/nft_image/nft_image_event.dart, lib/bloc/nft_image/nft_image_state.dart
Introduces a Bloc for NFT image loading with fallback and retry logic, defines event and state classes for managing image load requests, failures, retries, and resets, and tracks media type and URL candidates.
IPFS Gateway Management Utility
lib/shared/utils/ipfs_gateway_manager.dart, lib/shared/constants/ipfs_constants.dart
Adds IpfsGatewayManager to handle gateway selection, fallback, failure tracking, normalization, and URL accessibility testing. Centralizes gateway lists and cooldown settings in IpfsConstants.
Bloc Root Provider
lib/bloc/app_bloc_root.dart
Registers IpfsGatewayManager as a repository provider at the app root for dependency injection throughout the widget tree.
NFT Model Update
lib/model/nft.dart
Simplifies the imageUrl getter in NftToken to return the raw URL, removing normalization logic and delegating it to the Bloc layer.
NFT Image Widget Refactor
lib/views/nfts/common/widgets/nft_image.dart
Refactors the NftImage widget to use Bloc-based fallback loading for images and videos, updates parameter names, and introduces stateful widgets for handling loading, errors, and retries with support for multiple media types.
Parameter Name Alignment
lib/views/nfts/details_page/desktop/nft_details_page_desktop.dart, lib/views/nfts/details_page/mobile/nft_details_page_mobile.dart, lib/views/nfts/details_page/withdraw/nft_withdraw_success.dart, lib/views/nfts/nft_list/nft_list_item.dart, lib/views/nfts/nft_transactions/common/widgets/nft_txn_media.dart
Updates all usages of NftImage to use the new imageUrl parameter name, ensuring consistency with the refactored widget.
Unit Testing for Gateway Manager
test_units/tests/utils/ipfs_gateway_manager_test.dart, test_units/main.dart
Adds comprehensive unit tests for IpfsGatewayManager, covering gateway extraction, normalization, fallback logic, failure tracking, and platform-specific behaviors; integrates the new tests into the main test suite.

Sequence Diagram(s)

sequenceDiagram
    participant UI as NftImage Widget
    participant Bloc as NftImageBloc
    participant Gateway as IpfsGatewayManager

    UI->>Bloc: NftImageLoadRequested(imageUrl)
    Bloc->>Gateway: _generateAllUrls(imageUrl)
    Gateway-->>Bloc: [url1, url2, ...]
    Bloc->>Gateway: findWorkingUrl([url1, url2, ...])
    Gateway->>Gateway: Test url1, url2, ... (skip failed)
    Gateway-->>Bloc: workingUrl or null
    alt workingUrl found
        Bloc->>UI: emit Loaded(workingUrl)
    else no workingUrl
        Bloc->>UI: emit Exhausted(error)
    end
    UI->>Bloc: NftImageLoadFailed(failedUrl)
    Bloc->>Gateway: logGatewayAttempt(failedUrl, false)
    Bloc->>Gateway: find next working URL
    Gateway-->>Bloc: nextWorkingUrl or null
    alt nextWorkingUrl found
        Bloc->>UI: emit Retrying(nextWorkingUrl)
    else exhausted
        Bloc->>UI: emit Exhausted(error)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Suggested labels

enhancement, QA

Suggested reviewers

  • smk762
  • AndrewDelaney
  • CharlVS

Poem

A clever new trick for the NFT show,
With gateways and Blocs, the images flow.
If one link fails, another hops in—
Like a rabbit, persistent, determined to win!
Now art loads with bounce and with flair,
Thanks to fallback magic and circuit-breaker care.
🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/nft-image-loading

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jul 29, 2025

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

https://walletrc--pull-3020-merge-92xu8slr.web.app

(expires Mon, 11 Aug 2025 13:29:17 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: f66a4ff03faa546f12f0ae5a841bd9eff2714dcc

@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jul 29, 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.

@takenagain takenagain requested a review from Copilot July 29, 2025 22:58
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 introduces comprehensive IPFS gateway resolution, retry, and fallback mechanisms to improve NFT image loading reliability. The changes implement a sophisticated system for handling multiple IPFS gateways, circuit breaker patterns, and seamless URL fallbacks when NFT images fail to load.

Key changes:

  • New IpfsGatewayManager utility for IPFS URL resolution and gateway management with circuit breaker pattern
  • NftImageBloc for state management of image loading with automatic fallback between multiple gateways
  • Enhanced NftImage widget with automatic retry and fallback capabilities for both images and videos
  • Comprehensive test coverage for the new IPFS gateway management functionality

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
lib/shared/utils/ipfs_gateway_manager.dart Core IPFS gateway management utility with URL parsing, fallback logic, and circuit breaker pattern
lib/shared/constants/ipfs_constants.dart Configuration constants for IPFS gateways and timeout settings
lib/bloc/nft_image/nft_image_bloc.dart BLoC for managing NFT image loading state with automatic fallbacks
lib/bloc/nft_image/nft_image_state.dart State definitions for image loading with fallback mechanisms
lib/bloc/nft_image/nft_image_event.dart Events for image loading lifecycle management
lib/views/nfts/common/widgets/nft_image.dart Enhanced NFT image widget with automatic retry and fallback support
lib/model/nft.dart Simplified to return raw URLs, delegating normalization to the bloc
lib/bloc/app_bloc_root.dart Added IpfsGatewayManager as a repository provider
test_units/tests/utils/ipfs_gateway_manager_test.dart Comprehensive test suite for IPFS gateway manager functionality
test_units/main.dart Added test registration for IPFS gateway manager tests

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: 4

🧹 Nitpick comments (1)
lib/views/nfts/nft_transactions/common/widgets/nft_txn_media.dart (1)

29-32: Rename the local field for consistency

The widget property is still called imagePath, yet it’s now forwarded as imageUrl. Renaming keeps the API self-documenting and avoids future confusion.

-  final String? imagePath;
+  final String? imageUrl;-    required this.imagePath,
+    required this.imageUrl,-          child: NftImage(imageUrl: imagePath),
+          child: NftImage(imageUrl: imageUrl),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8f784f and 38ef68f.

📒 Files selected for processing (15)
  • lib/bloc/app_bloc_root.dart (2 hunks)
  • lib/bloc/nft_image/nft_image_bloc.dart (1 hunks)
  • lib/bloc/nft_image/nft_image_event.dart (1 hunks)
  • lib/bloc/nft_image/nft_image_state.dart (1 hunks)
  • lib/model/nft.dart (1 hunks)
  • lib/shared/constants/ipfs_constants.dart (1 hunks)
  • lib/shared/utils/ipfs_gateway_manager.dart (1 hunks)
  • lib/views/nfts/common/widgets/nft_image.dart (2 hunks)
  • lib/views/nfts/details_page/desktop/nft_details_page_desktop.dart (1 hunks)
  • lib/views/nfts/details_page/mobile/nft_details_page_mobile.dart (2 hunks)
  • lib/views/nfts/details_page/withdraw/nft_withdraw_success.dart (1 hunks)
  • lib/views/nfts/nft_list/nft_list_item.dart (1 hunks)
  • lib/views/nfts/nft_transactions/common/widgets/nft_txn_media.dart (1 hunks)
  • test_units/main.dart (2 hunks)
  • test_units/tests/utils/ipfs_gateway_manager_test.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
test_units/main.dart (5)

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/http_head_time_provider_test.dart:8-24
Timestamp: 2025-05-08T19:05:13.083Z
Learning: In the Komodo Wallet project, test functions are defined in individual files under test_units/tests/ but are executed through the central entry point in test_units/main.dart, so individual test files don't need their own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:2-3
Timestamp: 2025-05-01T21:00:36.970Z
Learning: It's acceptable to use unconditional dart:io imports in the Komodo wallet codebase when the usage is guarded by !kIsWeb conditional checks that prevent the platform-specific code from being executed in web environments.

lib/bloc/app_bloc_root.dart (2)

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #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.

test_units/tests/utils/ipfs_gateway_manager_test.dart (3)

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/http_head_time_provider_test.dart:8-24
Timestamp: 2025-05-08T19:05:13.083Z
Learning: In the Komodo Wallet project, test functions are defined in individual files under test_units/tests/ but are executed through the central entry point in test_units/main.dart, so individual test files don't need their own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

lib/bloc/nft_image/nft_image_state.dart (1)

Learnt from: takenagain
PR: #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.

lib/shared/utils/ipfs_gateway_manager.dart (1)

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:2-3
Timestamp: 2025-05-01T21:00:36.970Z
Learning: It's acceptable to use unconditional dart:io imports in the Komodo wallet codebase when the usage is guarded by !kIsWeb conditional checks that prevent the platform-specific code from being executed in web environments.

lib/views/nfts/common/widgets/nft_image.dart (3)

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:2-3
Timestamp: 2025-05-01T21:00:36.970Z
Learning: It's acceptable to use unconditional dart:io imports in the Komodo wallet codebase when the usage is guarded by !kIsWeb conditional checks that prevent the platform-specific code from being executed in web environments.

lib/bloc/nft_image/nft_image_bloc.dart (2)

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #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.

⏰ 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). (4)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: Build Desktop (windows)
🔇 Additional comments (27)
lib/shared/constants/ipfs_constants.dart (1)

7-13: Verify gateway style alignment with IpfsGatewayManager URL builder

All listed gateways are path-style (…/ipfs/). If IpfsGatewayManager ever switches between path- and sub-domain-style resolution, keeping a mixed list will break URL generation. Please double-check that the normalization logic expects path-style gateways only, or split the constants into two explicit lists.

lib/views/nfts/details_page/desktop/nft_details_page_desktop.dart (1)

36-37: Renamed parameter looks correct

NftImage(imageUrl: …) matches the new constructor. No further action required.

lib/views/nfts/details_page/withdraw/nft_withdraw_success.dart (1)

71-76: Parameter update confirmed

NftImage(imageUrl: nft.imageUrl) aligns with the refactored widget API.

lib/views/nfts/nft_list/nft_list_item.dart (1)

73-76: Parameter update confirmed

NftImage(imageUrl: widget.nft.imageUrl) aligns with the new constructor. No issues spotted.

test_units/main.dart (1)

36-36: LGTM! Proper test integration following established patterns.

The new IPFS gateway test is correctly integrated into the centralized test runner, following the project's established pattern of defining tests in individual files but executing them through the main test entry point.

Also applies to: 76-76

lib/views/nfts/details_page/mobile/nft_details_page_mobile.dart (1)

102-102: LGTM! Parameter name updates maintain consistency.

The parameter renames from imagePath to imageUrl correctly align with the refactored NftImage widget signature and support the new bloc-based image loading approach.

Also applies to: 156-156

lib/bloc/app_bloc_root.dart (2)

69-69: LGTM! Clean import addition.

The import for IpfsGatewayManager is properly placed with other utility imports.


156-158: Excellent dependency injection setup with clear documentation.

The IpfsGatewayManager is correctly positioned near the root of the widget tree to enable app-wide access to the shared instance. The explanatory comment clearly documents the rationale for keeping the in-memory cache of failing URLs at this level, which is crucial for the circuit breaker functionality.

lib/model/nft.dart (1)

78-78: Excellent architectural improvement with clear separation of concerns.

Simplifying the imageUrl getter to return raw data while delegating URL normalization and fallback handling to the bloc layer is a sound design decision. This enables the IpfsGatewayManager and NftImageBloc to implement sophisticated retry and fallback mechanisms while keeping the model focused on data representation.

test_units/tests/utils/ipfs_gateway_manager_test.dart (13)

6-8: LGTM! Proper test structure following project conventions.

The main function correctly calls the test function, following the established pattern in the Komodo Wallet project where individual test files are executed through a central test runner.


10-16: Excellent test setup with proper initialization.

The test group structure and setUp method provide clean initialization for each test case, ensuring test isolation.


18-61: Comprehensive constructor and configuration testing.

The tests thoroughly cover default gateway selection, custom gateway configuration, and failure cooldown settings. The platform-specific testing with kIsWeb ensures correct behavior across different environments.


63-120: Thorough IPFS URL detection coverage.

The test suite covers all IPFS URL formats including protocol URLs (ipfs://), gateway format URLs, subdomain format URLs, and properly handles edge cases like null/empty URLs and non-IPFS URLs.


122-191: Excellent CID extraction testing with comprehensive format coverage.

Tests properly validate CID and path extraction from various IPFS URL formats including protocol, gateway, and subdomain formats. The case-insensitive testing is particularly valuable for real-world robustness.


193-225: Solid gateway URL generation testing.

Tests ensure proper URL generation for both IPFS and non-IPFS content, with appropriate handling of edge cases and primary gateway selection.


227-251: Good URL normalization testing.

Tests validate that different IPFS URL formats are properly normalized to the preferred gateway format while preserving paths.


253-279: Well-designed fallback mechanism testing.

Tests ensure proper fallback behavior between gateways and appropriate handling of edge cases when no more fallbacks are available.


281-328: Excellent circuit breaker and failure tracking tests.

The comprehensive testing of failure tracking, cooldown periods, and reliable URL filtering ensures the circuit breaker functionality works as expected. The async test for cooldown expiration is particularly well-implemented.


330-346: Good gateway support validation testing.

Tests ensure proper validation of gateway support for different platforms.


348-396: Comprehensive edge case and error handling testing.

The extensive testing of malformed URLs, long URLs, and special characters ensures robust error handling. The graceful handling validation is crucial for production stability.


398-475: Valuable real-world example testing.

Testing with actual NFT metadata URLs, popular IPFS services, and various URL types provides confidence that the implementation will work with real-world data. The comprehensive coverage of both valid and invalid URLs is excellent.


477-509: Good performance and logging test coverage.

Tests ensure that logging functionality works correctly for both successful and failed gateway attempts without throwing exceptions.

lib/bloc/nft_image/nft_image_event.dart (1)

1-63: Well-structured event classes for NFT image loading.

The event hierarchy is clean and follows Bloc best practices. All events properly extend Equatable with correct props implementation for value equality.

lib/views/nfts/common/widgets/nft_image.dart (1)

1-287: Excellent refactoring to Bloc pattern for robust image loading.

The implementation properly integrates the NftImageBloc for fallback support and maintains clean separation of concerns between image and video handling widgets.

lib/bloc/nft_image/nft_image_bloc.dart (2)

32-39: Consider fallback for servers that don't support HEAD requests.

Some servers or IPFS gateways might not properly support HEAD requests or return different status codes.

Consider adding a fallback to GET requests with minimal data fetching if HEAD fails, or document which gateways are known to support HEAD requests properly.


11-253: Well-architected BLoC with comprehensive fallback logic.

The implementation properly manages state transitions, handles timer cleanup, and integrates circuit breaker pattern through IpfsGatewayManager. The retry logic with configurable attempts and timeouts provides good resilience.

lib/shared/utils/ipfs_gateway_manager.dart (1)

4-197: Comprehensive IPFS gateway management with circuit breaker pattern.

The implementation provides robust URL normalization, platform-specific gateway selection, and failure tracking with cooldown. The regex patterns correctly handle various IPFS URL formats.

@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jul 29, 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.

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: 1

♻️ Duplicate comments (1)
test_units/tests/utils/ipfs_gateway_manager_test.dart (1)

395-395: The base64 data URL is very long and makes the test code hard to read.

Consider extracting it to a constant at the top of the file for better readability.

+  // At the top of testIpfsGatewayManager function
+  const base64ImageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';
+
   // In the test
-            'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==',
+            base64ImageUrl,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38ef68f and a2c983c.

📒 Files selected for processing (4)
  • lib/bloc/nft_image/nft_image_bloc.dart (1 hunks)
  • lib/shared/utils/ipfs_gateway_manager.dart (1 hunks)
  • lib/views/nfts/common/widgets/nft_image.dart (2 hunks)
  • test_units/tests/utils/ipfs_gateway_manager_test.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
test_units/tests/utils/ipfs_gateway_manager_test.dart (3)

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/http_head_time_provider_test.dart:8-24
Timestamp: 2025-05-08T19:05:13.083Z
Learning: In the Komodo Wallet project, test functions are defined in individual files under test_units/tests/ but are executed through the central entry point in test_units/main.dart, so individual test files don't need their own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

Learnt from: takenagain
PR: #2611
File: test_units/tests/system_health/system_clock_repository_test.dart:7-8
Timestamp: 2025-05-08T19:07:13.442Z
Learning: In the Komodo Wallet project, test files are structured to define test functions that are called from a central test runner in test_units/main.dart, rather than each test file having its own main() function.

lib/views/nfts/common/widgets/nft_image.dart (3)

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:2-3
Timestamp: 2025-05-01T21:00:36.970Z
Learning: It's acceptable to use unconditional dart:io imports in the Komodo wallet codebase when the usage is guarded by !kIsWeb conditional checks that prevent the platform-specific code from being executed in web environments.

lib/shared/utils/ipfs_gateway_manager.dart (3)

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:2-3
Timestamp: 2025-05-01T21:00:36.970Z
Learning: It's acceptable to use unconditional dart:io imports in the Komodo wallet codebase when the usage is guarded by !kIsWeb conditional checks that prevent the platform-specific code from being executed in web environments.

Learnt from: takenagain
PR: #2608
File: lib/views/fiat/webview_dialog.dart:50-55
Timestamp: 2025-05-01T21:00:56.962Z
Learning: kIsWasm is a valid constant in Flutter 3.22+ (released May 2024) that detects if an application is running on WebAssembly. It complements kIsWeb for more precise platform detection.

Learnt from: takenagain
PR: #2608
File: lib/bloc/fiat/fiat_onramp_form/fiat_form_bloc.dart:208-225
Timestamp: 2025-05-01T20:56:36.180Z
Learning: The kIsWasm constant is available in Flutter version 3.22+ (released May 2024) and is used to detect if an application is running on the WebAssembly backend. When writing platform-specific code, use both kIsWeb and kIsWasm checks to properly handle both JavaScript and WebAssembly compilation targets.

lib/bloc/nft_image/nft_image_bloc.dart (2)

Learnt from: takenagain
PR: #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.

Learnt from: takenagain
PR: #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.

⏰ 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). (3)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Mobile (Android)
🔇 Additional comments (5)
test_units/tests/utils/ipfs_gateway_manager_test.dart (1)

10-465: Excellent test coverage!

The test suite comprehensively covers all aspects of the IpfsGatewayManager including initialization, URL detection, extraction, normalization, failure tracking with cooldown, platform-specific behavior, edge cases, and real-world scenarios. The tests are well-organized and thorough.

lib/views/nfts/common/widgets/nft_image.dart (1)

176-270: Well-implemented video player with proper lifecycle management!

The deferred initialization of VideoPlayerController until a valid URL is available properly addresses the previous concern about empty URI initialization. The implementation correctly handles URL changes, disposes resources, and manages state transitions.

lib/bloc/nft_image/nft_image_bloc.dart (1)

10-231: Robust Bloc implementation with excellent error handling!

The NftImageBloc is well-structured with:

  • Proper dependency injection of IpfsGatewayManager
  • Comprehensive error handling and retry logic with configurable limits
  • Clean state transitions and timer management
  • Appropriate resource cleanup in the close() method

The fallback mechanism through multiple URLs with circuit breaker pattern is a great approach for improving NFT media loading reliability.

lib/shared/utils/ipfs_gateway_manager.dart (2)

79-110: Excellent IPFS URL extraction logic!

The _extractContentId method comprehensively handles all IPFS URL formats:

  • Protocol format (ipfs://)
  • Gateway format with proper pattern precedence
  • Subdomain format with path preservation
  • Generic /ipfs/ path detection
  • Case-insensitive matching throughout

The implementation correctly prioritizes gateway pattern matching before subdomain to avoid conflicts.


157-190: Well-implemented circuit breaker pattern!

The failure tracking mechanism effectively implements a circuit breaker pattern with:

  • Thread-safe operations using mutex protection
  • Configurable cooldown periods for failed URLs
  • Automatic cleanup of expired failures
  • Efficient filtering of reliable gateways

This approach prevents repeated attempts on failing gateways while allowing recovery after the cooldown period.

@takenagain takenagain marked this pull request as ready for review July 29, 2025 23:35
@takenagain takenagain added the QA Ready for QA Testing label Jul 29, 2025
@takenagain takenagain requested a review from smk762 July 29, 2025 23:37
Copy link
Copy Markdown
Collaborator

@smk762 smk762 left a comment

Choose a reason for hiding this comment

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

Errors which prompted issue for PR no longer seen in app, but seems now that though image may load initially, it falls away once you start to navigate.

vokoscreenNG-2025-07-31_04-43-00.mp4

takenagain and others added 6 commits August 4, 2025 11:40
* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@takenagain
Copy link
Copy Markdown
Contributor Author

Errors which prompted issue for PR no longer seen in app, but seems now that though image may load initially, it falls away once you start to navigate.

The issue with the disappearing image should be resolved. @smk762 could you give it another spin to confirm that everything looks good?

@smk762 smk762 self-requested a review August 6, 2025 09:05
Copy link
Copy Markdown
Collaborator

@smk762 smk762 left a comment

Choose a reason for hiding this comment

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

LGTM thanks. Disappearing image issue resolved 🍻

Copy link
Copy Markdown
Collaborator

@CharlVS CharlVS left a comment

Choose a reason for hiding this comment

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

image

*If the code meets our strict standards

@CharlVS CharlVS merged commit 22a0833 into dev Aug 6, 2025
9 of 13 checks passed
@CharlVS CharlVS deleted the bugfix/nft-image-loading branch August 6, 2025 12:48
smk762 pushed a commit that referenced this pull request Aug 8, 2025
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
smk762 pushed a commit that referenced this pull request Aug 12, 2025
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
smk762 pushed a commit that referenced this pull request Aug 12, 2025
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
smk762 pushed a commit that referenced this pull request Aug 12, 2025
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
cursor bot pushed a commit that referenced this pull request Aug 20, 2025
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CharlVS added a commit that referenced this pull request Sep 10, 2025
* fix impossible nested condition logic

* handle uninitialized logger exceptions gratefully

* caches `typeName` to avoid unneccesary `getCoinTypeName` calls

* adds caching for `isParent`

* set parents as native; use cached coin values

* special case to cover ARB

* chore: roll SDK (#3036)

Roll SDK for critical KMD API pricing fix

* chore: remove FEEDBACK_TEST_URL references

* fix(ui): close dropdown on window resize

* Fix null safety issues in UiDropdown widget

Co-authored-by: charl <charl@vanstaden.info>

* fix(build): correct env vars passing to Docker and Dart via --dart-define (#3037)

* refactor: simplify Docker env vars and build command logic

- Remove unnecessary environment variables from Docker container
- Keep only GITHUB_API_PUBLIC_READONLY_TOKEN as env var
- Replace hardcoded build logic with conditional credential handling
- Add proper validation for Trello and Cloudflare feedback services
- Use dart-define flags instead of environment variables for build configs
- Add warning messages for incomplete credential sets

* fix executable rights on build.sh

* remove the redundant FEEDBACK_TEST_URL, as it will no longer be used in the GUI

* swap BUILD_COMMAND and BUILD_CMD (important)

BUILD_CMD, which is built dynamically with --dart-define= arguments, should be called last (not during the assets-fetch stage) to ensure the app is actually built with the required defines and that all String.fromEnvironment(...) statements in the Dart code work as expected.

* fix(nft): add IPFS gateway resolution, retry, and fallback to improve NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(build): add --no-web-resources-cdn to the web build in build.sh (#3055)

* Remove .dgph build artifacts from iOS project (#3058)

* remove dgph binaries

* Ignore .dgph build artifacts in iOS

* fix arb parent ticker

* include qtum parent

* chore(sdk): bump submodule to 170aab4 for parent display name suffix

Pulls in AssetId.displayName and CoinSubClass.tokenStandardSuffix

* feat(ui): disambiguate parent chain names via SDK displayName

- Use AssetId.displayName for top-level assets (SDK)\n- Update UI to show e.g. Ethereum (ARB20) for parents\n- Keep protocol pill consistent using coin.typeName (NATIVE for parents)\n- Search compares against displayName\n\nRefs: #2988 (comment)

---------

Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: charl <charl@vanstaden.info>
Co-authored-by: DeckerSU <deckersu@protonmail.com>
Co-authored-by: Francois <takenagain@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@CharlVS CharlVS mentioned this pull request Oct 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working QA Ready for QA Testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants