Skip to content

Conversation

@HashEngineering
Copy link
Collaborator

@HashEngineering HashEngineering commented Oct 23, 2025

Issue being fixed or feature implemented

Related PR's and Dependencies

Screenshots / Videos

How Has This Been Tested?

  • QA (Mobile Team)

Checklist:

  • I have performed a self-review of my own code and added comments where necessary
  • I have added or updated relevant unit/integration/functional/e2e tests

Summary by CodeRabbit

  • New Features

    • Added transaction metadata status display in settings, showing save progress and last saved date.
    • Improved conditional visibility for transaction metadata settings based on account status.
  • Bug Fixes

    • Enhanced transaction metadata handling for platform synchronization.
    • Fixed testnet mode detection for platform sync configuration.

@HashEngineering HashEngineering self-assigned this Oct 23, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 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

The pull request restructures Settings UI by migrating SettingsFragment from ui/more to ui package and integrating transaction metadata UI handling. PlatformSyncService updates hash handling to use reversed byte format and expands testnet detection. A theme typography constant is removed. SettingsViewModel and SettingsScreen are enhanced to expose transaction metadata visibility and subtitle state.

Changes

Cohort / File(s) Summary
Theme cleanup
common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt
Removed OverlineCaptionMedium TextStyle declaration (fontSize 12.sp, lineHeight 16.sp, fontFamily interRegular, fontWeight 400).
Platform sync hash and testnet handling
wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt
Updated PUSH_PERIOD and CUTOFF_MIN/CUTOFF_MAX to consider Constants.IS_TESTNET_BUILD alongside BuildConfig.DEBUG. Reversed transaction hash handling: use Sha256Hash.wrapReversed(metadata.txId) for lookups and txIdAsHash.reversedBytes for platform publishing. Changed key index calculation from transactionMetadataChangeCacheDao.count() + transactionMetadataDocumentDao.countAllRequests() to 1 + transactionMetadataDocumentDao.countAllRequests(). Changed itemsToSave from var to val.
Settings UI state management
wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt
Added transactionMetadataVisible: Boolean and transactionMetadataSubtitle: String? fields to SettingsUIState. Made blockchainIdentityConfig a private constructor property. Added observation of blockchainIdentityConfig.identityData.creationComplete to set visibility. Added public method updateTransactionMetadataSubtitle(subtitle: String?).
Settings Compose UI
wallet/src/de/schildbach/wallet/ui/more/SettingsScreen.kt
Added conditional visibility guard uiState.transactionMetadataVisible to Transaction Metadata menu item. Updated item title to use string resource and added subtitle from uiState.transactionMetadataSubtitle. Extended preview state to include metadata visibility and subtitle.
Settings Fragment migration and enhancement
wallet/src/de/schildbach/wallet/ui/SettingsFragment.kt
New file: Added setupTransactionMetadataObservers() to initialize view model, observe publish operations, and update UI subtitle. Added setTransactionMetadataText(isSaving, saveProgress) to compute subtitle from saving state or last saved date. Added transactionMetadataSettingsViewModel property via viewModels(). Injected walletApplication and added dateFormat field. Replaced placeholder onTransactionMetadataClick() with navigation logic (to transaction_metadata_settings_fragment or dialog with flags).
Settings Fragment deletion
wallet/src/de/schildbach/wallet/ui/more/SettingsFragment.kt
File deleted: Entire class removed, including all onViewCreated setup, observers, dialogs, navigation, and helper methods.
Transaction metadata dialog annotation
wallet/src/de/schildbach/wallet/ui/more/TransactionMetadataDialog.kt
Added @OptIn(ExperimentalCoroutinesApi::class) annotation to onViewCreated() method.

Sequence Diagram

sequenceDiagram
    participant UI as SettingsFragment
    participant VM as TransactionMetadataSettingsViewModel
    participant DB as TransactionMetadataDao
    participant Platform as PlatformSyncService

    UI->>VM: setupTransactionMetadataObservers()
    VM->>VM: Load last work IDs
    VM->>DB: Query last saved timestamp
    
    Platform->>Platform: Trigger metadata publishing
    Platform->>DB: Update transaction metadata
    Platform->>VM: Emit publish result
    
    VM->>UI: Update subtitle LiveData
    UI->>UI: setTransactionMetadataText(isSaving, progress)
    UI->>UI: Refresh subtitle display (date or progress)
    
    alt User taps transaction metadata
        UI->>VM: Check visibility state
        alt Info already shown
            UI->>UI: Navigate to settings fragment
        else First time
            UI->>UI: Show info dialog
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span multiple files with a mix of architectural refactoring (file migration), new UI integration logic (observers, subtitle updates, navigation), hash handling updates in the sync service, and UI state management extensions. While individual cohorts are straightforward, the integration across Settings components and the hash reversal logic require careful review for consistency and correctness.

Poem

🐰 Hashes reversed in sync, settings rearranged with care,
Metadata observers dance, their subtitles fill the air,
From ui/more to ui, the fragments take their flight,
Platform's LE format shines, our transactions burning bright!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: finalize txmetadata and align with specification" is specific and clearly summarizes the primary objective of the changeset. The vast majority of modifications across multiple files (PlatformSyncService.kt, SettingsFragment.kt, SettingsScreen.kt, SettingsViewModel.kt, and TransactionMetadataDialog.kt) are directly focused on transaction metadata functionality, UI integration, hash handling, and state management. While there is one minor unrelated change in MyTheme.kt (removal of a TextStyle declaration), this represents an insignificant portion of the overall changeset and does not undermine or contradict the main theme. A developer scanning the repository history would clearly understand that the primary focus of this PR is finalizing transaction metadata implementation and specification alignment.

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.

@HashEngineering
Copy link
Collaborator Author

@coderabbitai please review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 2025

@HashEngineering: I'll review the changes in this PR.


🧠 Learnings used
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1422
File: common/src/main/java/org/dash/wallet/common/util/Constants.kt:68-69
Timestamp: 2025-08-25T15:00:20.777Z
Learning: HashEngineering prefers to keep HTTP logging enabled in release mode (using log.info instead of gating with BuildConfig.DEBUG) to debug production errors, even though this may leak URLs in production logs. This is a deliberate trade-off for debugging purposes in the Dash wallet project.

Learnt from: HashEngineering
PR: dashpay/dash-wallet#1410
File: wallet/src/de/schildbach/wallet/data/InvitationLinkData.kt:79-84
Timestamp: 2025-07-12T07:12:04.769Z
Learning: HashEngineering prefers to handle defensive validation improvements for URI parsing in follow-up PRs rather than including them in the current PR when the main focus is on replacing Firebase with AppsFlyer.
✅ 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
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: 2

🧹 Nitpick comments (8)
wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt (2)

1034-1061: Ensure reversed bytes match platform's expected hash format.

When publishing metadata to platform, the code now uses it.txId.reversedBytes (line 1045). This should be consistent with:

  1. How platform expects to receive transaction hashes
  2. The reversal applied when receiving hashes (line 808)

If your internal storage uses little-endian and platform expects big-endian, this is correct. However, this must align with the platform specification and be verified against the changes at line 808.

Consider adding documentation or constants to clarify the byte order convention:

// At the top of the file or in a companion object
/**
 * Platform stores tx hashes in big-endian (display format).
 * Internal storage uses little-endian (Sha256Hash native format).
 * Use wrapReversed when receiving from platform.
 * Use reversedBytes when sending to platform.
 */

1264-1264: Good refactor: Use val for immutable variable.

Correctly changed from var to val since itemsToSave is never reassigned after initialization.

wallet/src/de/schildbach/wallet/ui/more/TransactionMetadataDialog.kt (1)

50-68: Scope and opt-in hygiene

  • onViewCreated doesn’t use experimental coroutines APIs; drop @OptIn here to reduce opt-in spread.
  • Prefer viewLifecycleOwner.lifecycleScope for view-tied work.

Apply:

-    @OptIn(ExperimentalCoroutinesApi::class)
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         ...
-        lifecycleScope.launch {
+        viewLifecycleOwner.lifecycleScope.launch {
             viewModel.setTransactionMetadataInfoShown()
         }
wallet/src/de/schildbach/wallet/ui/more/SettingsScreen.kt (3)

90-92: Use lifecycle-aware state collection in Compose

Prefer collectAsStateWithLifecycle to avoid collecting when the UI is not started/resumed.

-    val uiState by uiStateFlow.collectAsState()
+    val uiState by uiStateFlow.collectAsStateWithLifecycle()

Requires androidx.lifecycle:lifecycle-runtime-compose.


120-121: Avoid per-recomposition allocations

Memoize DecimalFormat.

-    val decimalFormat = DecimalFormat("0.000")
+    val decimalFormat = remember { DecimalFormat("0.000") }

220-227: Null-safe subtitle and visibility guard

  • Ensure MenuItem.subtitle accepts null. If not, pass an empty string or omit the subtitle.
  • Visibility is correctly gated by SUPPORTS_TXMETADATA and uiState.transactionMetadataVisible.

If non-null required:

-    subtitle = uiState.transactionMetadataSubtitle,
+    subtitle = uiState.transactionMetadataSubtitle ?: "",
wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt (1)

194-196: Avoid unnecessary UI updates

Skip update if unchanged to prevent recompositions.

-    fun updateTransactionMetadataSubtitle(subtitle: String?) {
-        _uiState.value = _uiState.value.copy(transactionMetadataSubtitle = subtitle)
-    }
+    fun updateTransactionMetadataSubtitle(subtitle: String?) {
+        if (_uiState.value.transactionMetadataSubtitle != subtitle) {
+            _uiState.value = _uiState.value.copy(transactionMetadataSubtitle = subtitle)
+        }
+    }
wallet/src/de/schildbach/wallet/ui/SettingsFragment.kt (1)

239-254: Simplify observer wiring and bind to view lifecycle

Avoid nested observe and use viewLifecycleOwner.lifecycleScope for view-tied coroutines.

-        lifecycleScope.launch {
+        viewLifecycleOwner.lifecycleScope.launch {
             transactionMetadataSettingsViewModel.loadLastWorkId()
         }
-        transactionMetadataSettingsViewModel.lastSaveWorkId.filterNotNull().observe(viewLifecycleOwner) { workId ->
-            transactionMetadataSettingsViewModel.observePublishOperation(workId).observe(viewLifecycleOwner) {
-                val progress = it.data?.progress?.let { data -> BaseWorker.extractProgress(data) } ?: 0
-                setTransactionMetadataText(progress != 100 && progress != -1, progress)
-            }
-        }
+        transactionMetadataSettingsViewModel.lastSaveWorkId
+            .filterNotNull()
+            .onEach { workId ->
+                transactionMetadataSettingsViewModel.observePublishOperation(workId)
+                    .onEach { state ->
+                        val progress = state.data?.progress?.let { d -> BaseWorker.extractProgress(d) } ?: 0
+                        setTransactionMetadataText(progress != 100 && progress != -1, progress)
+                    }
+                    .launchIn(viewLifecycleOwner.lifecycleScope)
+            }
+            .launchIn(viewLifecycleOwner.lifecycleScope)

Add:

import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.launchIn
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63b2520 and 2407b76.

📒 Files selected for processing (7)
  • common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt (0 hunks)
  • wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt (5 hunks)
  • wallet/src/de/schildbach/wallet/ui/SettingsFragment.kt (4 hunks)
  • wallet/src/de/schildbach/wallet/ui/more/SettingsFragment.kt (0 hunks)
  • wallet/src/de/schildbach/wallet/ui/more/SettingsScreen.kt (2 hunks)
  • wallet/src/de/schildbach/wallet/ui/more/SettingsViewModel.kt (4 hunks)
  • wallet/src/de/schildbach/wallet/ui/more/TransactionMetadataDialog.kt (1 hunks)
💤 Files with no reviewable changes (2)
  • common/src/main/java/org/dash/wallet/common/ui/components/MyTheme.kt
  • wallet/src/de/schildbach/wallet/ui/more/SettingsFragment.kt
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1422
File: common/src/main/java/org/dash/wallet/common/util/Constants.kt:68-69
Timestamp: 2025-08-25T15:00:20.777Z
Learning: HashEngineering prefers to keep HTTP logging enabled in release mode (using log.info instead of gating with BuildConfig.DEBUG) to debug production errors, even though this may leak URLs in production logs. This is a deliberate trade-off for debugging purposes in the Dash wallet project.
Learnt from: HashEngineering
PR: dashpay/dash-wallet#1410
File: wallet/src/de/schildbach/wallet/data/InvitationLinkData.kt:79-84
Timestamp: 2025-07-12T07:12:04.769Z
Learning: HashEngineering prefers to handle defensive validation improvements for URI parsing in follow-up PRs rather than including them in the current PR when the main focus is on replacing Firebase with AppsFlyer.
🔇 Additional comments (6)
wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt (3)

155-158: LGTM! Testnet timing configuration improved.

The addition of Constants.IS_TESTNET_BUILD to the timing conditions appropriately enables shorter push periods and cutoff intervals for testnet builds, facilitating faster testing cycles without requiring DEBUG mode.


1064-1069: Verify the key index calculation aligns with the specification.

The key index calculation changed significantly from:

transactionMetadataChangeCacheDao.count() + transactionMetadataDocumentDao.countAllRequests()

to:

1 + transactionMetadataDocumentDao.countAllRequests()

This removes the count of cached (unpublished) items from the calculation. This change could have implications:

  1. Key reuse risk: If cached items exist but aren't counted, subsequent publishes might reuse the same key indices.
  2. Derivation path consistency: The constant 1 as the base suggests a deliberate starting point, but the rationale isn't clear.
  3. Alignment with specification: Given the PR title mentions "align with specification," this might be intentional.

Please confirm:

  • Does this match the txmetadata specification's key derivation requirements?
  • Are there scenarios where cached items could cause key index collisions?
  • Is the base of 1 instead of 0 intentional?

Based on learnings (as the PR description mentions finalizing txmetadata and aligning with specification).


808-828: Hash byte order handling is correct and consistent.

The change to wrapReversed() is appropriate. The codebase demonstrates a symmetric and consistent pattern:

  • Receiving from platform (line 808): Sha256Hash.wrapReversed(metadata.txId) converts platform's big-endian format to little-endian for storage
  • Sending to platform (line 1045): it.txId.reversedBytes converts from internal little-endian storage back to big-endian for the platform protocol
  • Explicit confirmation (lines 810, 1045): Both locations explicitly state "tx hash is stored in LE"
  • Consistent usage: All subsequent database operations (lines 809–1017) use the converted txIdAsHash for DAO queries and entity creation

This follows Bitcoin protocol conventions: hashes are transmitted in big-endian (wire format) but stored internally in little-endian. The symmetric reversal pattern on send/receive confirms the implementation is correct.

wallet/src/de/schildbach/wallet/ui/more/SettingsScreen.kt (1)

264-267: Preview looks good

Preview seeds the new TX metadata state; helpful for design review.

wallet/src/de/schildbach/wallet/ui/SettingsFragment.kt (1)

119-137: ****

The review comment misunderstands SafeArgs behavior. The nav graph defines arguments as first_time and use_navigation (snake_case), and the code correctly uses these exact names in the bundleOf() call. SafeArgs does not convert snake_case XML to camelCase properties—it preserves the declared names. The suggested fix using camelCase property names would break navigation because those properties don't exist. The code is correct as-is.

Likely an incorrect or invalid review comment.

wallet/src/de/schildbach/wallet/ui/more/TransactionMetadataDialog.kt (1)

75-78: The review comment is incorrect—no issues found

The show(activity) method is properly defined in the parent class OffsetDialogFragment (lines 115-117) and correctly delegates to the standard show(FragmentManager, String) API via activity.supportFragmentManager. There is no recursion, no compilation risk, and no need to refactor. The code works as intended through inheritance.

Likely an incorrect or invalid review comment.

Copy link

@abaranouski abaranouski left a comment

Choose a reason for hiding this comment

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

approved

@HashEngineering HashEngineering merged commit 4421444 into feature-txmetadata Nov 7, 2025
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants