feat: Update menu items on the More page#765
Conversation
…gation - Migrate all menu items to use the new MenuItem component - Update styles for MenuItemsList - Replace all menu item icons with updated assets - Change "Buy & Sell Dash" and "Explore" from bottom sheet to full page
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 27 minutes and 26 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds two SwiftUI screens (BuySellPortal, ExploreMenu), new SwiftUI components (TopIntro, CrowdNodeAPYBadge), converts several UIKit controllers to SwiftUI-hosted flows, updates MenuItem and color assets, and makes extensive asset catalog and Xcode project configuration changes. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
DashWallet/Sources/UI/Buy Sell/Model/BuySellPortalModel.swift (1)
93-110:⚠️ Potential issue | 🟡 MinorAvoid double delegate notifications.
self?.items = itemsalready triggersitems.didSet, which callsserviceItemsDidChange(). The extra call on Line 109 notifies legacy delegates twice for one data update.🧹 Proposed fix
DispatchQueue.main.async { self?.items = items - self?.delegate?.serviceItemsDidChange() }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/Model/BuySellPortalModel.swift around lines 93 - 110, The closure passed to serviceItemDataProvider.listenForData assigns self?.items = items which already triggers the items.didSet and calls delegate?.serviceItemsDidChange(); remove the subsequent explicit delegate?.serviceItemsDidChange() call inside that DispatchQueue.main.async block in the init so delegates are notified only once (locate the init, the listenForData closure, the items property with didSet, and remove the redundant call).
🧹 Nitpick comments (5)
DashWallet/Sources/UI/SwiftUI Components/TopIntro.swift (1)
22-22: Remove the explicitnilinitializer as it is unnecessary.Optional stored properties are implicitly initialized to
nil. While the SwiftLint ruleimplicit_optional_initializationis not currently enabled in the repository's.swiftlint.yml, removing the explicit= nilis a best-practice style improvement.🧹 Proposed fix
- var subtitle: String? = nil + var subtitle: String?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/SwiftUI` Components/TopIntro.swift at line 22, The stored property declaration "var subtitle: String? = nil" in TopIntro (symbol: subtitle) should drop the explicit "= nil" since optional properties are implicitly initialized to nil; update the property to "var subtitle: String?" to follow Swift style and avoid the unnecessary initializer.DashWallet/Sources/UI/Buy Sell/BuySellPortalScreen.swift (2)
89-117:.id(subtitle)onMenuItemindicates a state-retention issue inMenuItem.Attaching
.id(coinbaseSubtitle)/.id(upholdSubtitle)forces a newMenuItemidentity each time the subtitle string changes, which forces SwiftUI to rebuild the row. This is only necessary becauseMenuItem.subtitleViewis declared@Stateand captures its initial value in the init, so updates passed in by the parent are otherwise ignored.This works, but it has side effects (state inside
MenuItemgets reset, animations/transitions can flicker). Consider fixing the root cause inMenuItem.swift(makesubtitleViewa plain stored property, or recompute it inbody) instead of working around it here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalScreen.swift around lines 89 - 117, The root issue is that MenuItem.subtitleView is declared `@State` which captures its initial value and prevents parent updates, causing consumers (BuySellPortalScreen) to add .id(subtitle) to force rebuild; fix MenuItem by removing `@State` from subtitleView and make it a regular stored property or build the subtitle view inside MenuItem.body from the passed subtitle parameter (ensure the init assigns the plain property or recomputes it in body), and then remove the workaround .id(coinbaseSubtitle)/.id(upholdSubtitle) from BuySellPortalScreen so rows update without identity resets or flicker.
57-123: Extract duplicated card container styling.The Topper, Coinbase, and Uphold blocks each repeat the same
.padding(6)/.background(Color.secondaryBackground)/.clipShape(RoundedRectangle(...))/.shadow(...)/.padding(.horizontal, 20)stack. Consider extracting a smallViewModifieror container view (e.g.MenuCard) to keep this screen — and other migrated menus in the PR — consistent and easier to change.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalScreen.swift around lines 57 - 123, The three service blocks (Topper, Coinbase, Uphold) repeat the same container modifiers; extract them into a reusable MenuCard (either a ViewModifier named MenuCardModifier or a small container View named MenuCard) and wrap the inner content (the existing inner VStack that contains MenuItem) with it. Implement MenuCard to apply .padding(6) .background(Color.secondaryBackground) .clipShape(RoundedRectangle(cornerRadius:20, style:.continuous)) .shadow(color: Color.shadow, radius:20, x:0, y:5) .padding(.horizontal, 20), then replace the duplicated modifier chain on the Topper, Coinbase and Uphold VStacks with either .modifier(MenuCardModifier()) or by embedding their inner VStack inside MenuCard { ... } while keeping MenuItem, id(coinbaseSubtitle)/id(upholdSubtitle), frame(minHeight:56), and the existing trailingView/serviceBalanceView usage unchanged.DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift (1)
21-21: DuplicatemerchantTypesInfoDialogShownKeystring constant.
ExploreViewController.swiftalready defines the same UserDefaults key askMerchantTypesShown = "merchantTypesInfoDialogShownKey". Having two file-private constants with the same string value is a minor DRY violation and risks drift if one is ever renamed. Consider extracting a single shared constant (e.g., in anExploreConstantsenum or onUserDefaults.Key) used by both call sites, or remove it from the file that is being retired.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Explore` Dash/ExploreMenuScreen.swift at line 21, There is a duplicate string constant: replace the file-private kMerchantTypesShownKey with a single shared constant used by both locations (the existing kMerchantTypesShown in ExploreViewController and this file); create a single source of truth (e.g., add a shared ExploreConstants enum or an extension on UserDefaults.Key with merchantTypesInfoDialogShownKey) and update all references to use that shared symbol instead of the duplicate kMerchantTypesShownKey/kMerchantTypesShown identifiers so the key is defined once and referenced everywhere.DashWallet/Sources/UI/Buy Sell/BuySellPortalViewController.swift (1)
111-159: Delegate wiring is now effectively dead code; MARK comment is inaccurate.Two small nits in the migrated controller:
- Line 155 —
// MARK: PortalModelDelegateis out-of-date; the protocol isBuySellPortalModelDelegate. Renaming keeps the Xcode jump-bar accurate.serviceItemsDidChange()is now a no-op (SwiftUI observes@Published itemsdirectly viaBuySellPortalScreen), yetmodel.delegate = selfstill assigns the controller. If no other path needs the delegate callback, consider dropping both thedelegateassignment here and theBuySellPortalModelDelegateconformance, and removingdelegate?.serviceItemsDidChange()from the model — the@Publishedemission is already sufficient. Otherwise keep the stub but add a brief comment explaining why it's intentionally empty.🛠️ Minimal fix for the MARK
-// MARK: PortalModelDelegate +// MARK: - BuySellPortalModelDelegate🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalViewController.swift around lines 111 - 159, The controller still sets model.delegate = self and uses an empty BuySellPortalModelDelegate stub (serviceItemsDidChange()) while SwiftUI observes `@Published` items, and the MARK comment is misnamed; either remove the delegate wiring and protocol conformance and delete any delegate invocation in the model (delegate?.serviceItemsDidChange()), or keep the delegate but update the MARK to "// MARK: BuySellPortalModelDelegate" and add a one-line comment above func serviceItemsDidChange() explaining it is intentionally a no-op for compatibility; update BuySellPortalViewController, the model.delegate = self assignment, and any delegate calls in the model accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@DashWallet.xcodeproj/project.pbxproj`:
- Around line 9213-9219: Remove the unused empty PBXSourcesBuildPhase entry with
UUID 80B4C633F37C0A089A9C7138 from the project.pbxproj: locate the
PBXSourcesBuildPhase block named "Sources" (isa = PBXSourcesBuildPhase) with
that UUID and delete it, and confirm no PBXNativeTarget references its UUID in
any buildPhases arrays (remove any stale references if found) so the project
file no longer contains the orphaned empty sources phase.
- Line 1162: The project file contains 14 orphaned PBXBuildFile objects (IDs:
C9D2C70F2A320AA000D15901, C9D2C7272A320AA000D15901, C9D2C74C2A320AA000D15901,
C9D2C7692A320AA000D15901, C9D2C7AA2A320AA000D15901, C9D2C7B22A320AA000D15901,
C9D2C7C22A320AA000D15901, C9D2C7CB2A320AA000D15901, C9D2C84A2A320AA000D15901,
C9D2C86A2A320AA000D15901, C9D2C8992A320AA000D15901, C9D2C8E02A320AA000D15901,
C9D2C92B2A320AA000D15901, DE3A167A235B79D705C0A962) defined as "{isa =
PBXBuildFile; }" with no fileRef; remove each of these object definitions from
the PBXBuildFile section and also remove their occurrences from the build phase
"files = (...)" arrays in the Sources/Resources/Frameworks build phases where
they are referenced so no dangling IDs remain; after removal, verify the build
phase lists and that any legitimate files still have proper PBXBuildFile entries
with fileRef attributes.
- Around line 359-360: The new SwiftUI source files (BuySellPortalScreen.swift,
TopIntro.swift, ExploreMenuScreen.swift) are currently wired into the dashwallet
and dashpay targets but may be missing from other configuration targets
(testflight/testnet/WatchApp/TodayExtension); update the PBX build file entries
so each source has PBXBuildFile entries for every target that should include it
(or move these files into a shared source target/xcconfig if they must be
included everywhere), then locally build and run the following schemes to verify
no link-time errors: dashwallet.testnet, dashwallet.testflight, dashpay.testnet,
dashpay.testflight; specifically check the PBXBuildFile entries for the fileRefs
7B94B3697D7742BFA991B5CC (BuySellPortalScreen), the refs for TopIntro and
ExploreMenu, and ensure the WatchApp/TodayExtension targets do not erroneously
reference these SwiftUI files if they shouldn't.
In `@DashWallet/Sources/UI/Main/MainTabbarController.swift`:
- Line 234: The onShowGiftCard closure should select the Home tab before asking
homeController to present details; change the closure to first switch the tab
(e.g. call a local method like selectHome() or set self?.selectedIndex /
selectedViewController to the Home tab and ensure homeController is loaded) and
only then call self?.homeController?.showGiftCardDetails(txId: txId) so behavior
matches showGiftCard(_:).
In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift`:
- Around line 421-457: The pushed SwiftUI screens in showExplore, showSettings,
showTools, and showSecurity use bare UIHostingController instances which bypass
BaseNavigationController.willShow; create thin UIViewController subclasses
(e.g., ExploreHostingController, SettingsHostingController,
ToolsHostingController, SecurityHostingController) that host the respective
SwiftUI view in their view hierarchy, have initializers accepting the SwiftUI
root view (or the same params used when constructing
ExploreMenuScreen/SettingsScreen/ToolsMenuScreen/SecurityMenuScreen), and make
those subclasses conform to NavigationBarDisplayable or
NavigationStackControllable as required; then replace the
UIHostingController(...) instances with these wrapper controllers before setting
hidesBottomBarWhenPushed and vc.pushViewController(...).
In `@DashWallet/Sources/UI/SwiftUI` Components/MenuItem.swift:
- Around line 61-69: The MenuItem initializer currently forces subtitles to a
single line by calling .lineLimit(1) inside the subtitleView closure; remove the
hard-coded .lineLimit(1) and add a new parameter (e.g., subtitleLineLimit: Int?
= nil or = 2) to the MenuItem initializer so callers can opt into single-line
truncation; then apply .lineLimit(subtitleLineLimit) (or omit the modifier when
nil) where subtitleView is constructed so existing multi-line subtitles are
preserved and screens that need truncation (e.g., BuySellPortalScreen) can pass
subtitleLineLimit: 1.
---
Outside diff comments:
In `@DashWallet/Sources/UI/Buy` Sell/Model/BuySellPortalModel.swift:
- Around line 93-110: The closure passed to
serviceItemDataProvider.listenForData assigns self?.items = items which already
triggers the items.didSet and calls delegate?.serviceItemsDidChange(); remove
the subsequent explicit delegate?.serviceItemsDidChange() call inside that
DispatchQueue.main.async block in the init so delegates are notified only once
(locate the init, the listenForData closure, the items property with didSet, and
remove the redundant call).
---
Nitpick comments:
In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalScreen.swift:
- Around line 89-117: The root issue is that MenuItem.subtitleView is declared
`@State` which captures its initial value and prevents parent updates, causing
consumers (BuySellPortalScreen) to add .id(subtitle) to force rebuild; fix
MenuItem by removing `@State` from subtitleView and make it a regular stored
property or build the subtitle view inside MenuItem.body from the passed
subtitle parameter (ensure the init assigns the plain property or recomputes it
in body), and then remove the workaround
.id(coinbaseSubtitle)/.id(upholdSubtitle) from BuySellPortalScreen so rows
update without identity resets or flicker.
- Around line 57-123: The three service blocks (Topper, Coinbase, Uphold) repeat
the same container modifiers; extract them into a reusable MenuCard (either a
ViewModifier named MenuCardModifier or a small container View named MenuCard)
and wrap the inner content (the existing inner VStack that contains MenuItem)
with it. Implement MenuCard to apply .padding(6)
.background(Color.secondaryBackground)
.clipShape(RoundedRectangle(cornerRadius:20, style:.continuous)) .shadow(color:
Color.shadow, radius:20, x:0, y:5) .padding(.horizontal, 20), then replace the
duplicated modifier chain on the Topper, Coinbase and Uphold VStacks with either
.modifier(MenuCardModifier()) or by embedding their inner VStack inside MenuCard
{ ... } while keeping MenuItem, id(coinbaseSubtitle)/id(upholdSubtitle),
frame(minHeight:56), and the existing trailingView/serviceBalanceView usage
unchanged.
In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalViewController.swift:
- Around line 111-159: The controller still sets model.delegate = self and uses
an empty BuySellPortalModelDelegate stub (serviceItemsDidChange()) while SwiftUI
observes `@Published` items, and the MARK comment is misnamed; either remove the
delegate wiring and protocol conformance and delete any delegate invocation in
the model (delegate?.serviceItemsDidChange()), or keep the delegate but update
the MARK to "// MARK: BuySellPortalModelDelegate" and add a one-line comment
above func serviceItemsDidChange() explaining it is intentionally a no-op for
compatibility; update BuySellPortalViewController, the model.delegate = self
assignment, and any delegate calls in the model accordingly.
In `@DashWallet/Sources/UI/Explore` Dash/ExploreMenuScreen.swift:
- Line 21: There is a duplicate string constant: replace the file-private
kMerchantTypesShownKey with a single shared constant used by both locations (the
existing kMerchantTypesShown in ExploreViewController and this file); create a
single source of truth (e.g., add a shared ExploreConstants enum or an extension
on UserDefaults.Key with merchantTypesInfoDialogShownKey) and update all
references to use that shared symbol instead of the duplicate
kMerchantTypesShownKey/kMerchantTypesShown identifiers so the key is defined
once and referenced everywhere.
In `@DashWallet/Sources/UI/SwiftUI` Components/TopIntro.swift:
- Line 22: The stored property declaration "var subtitle: String? = nil" in
TopIntro (symbol: subtitle) should drop the explicit "= nil" since optional
properties are implicitly initialized to nil; update the property to "var
subtitle: String?" to follow Swift style and avoid the unnecessary initializer.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 615ed71b-0e46-4eb3-b85b-10ed7b1ed3b2
⛔ Files ignored due to path filters (189)
DashWallet/Resources/AppAssets.xcassets/Dash logo/dash-logo-black.imageset/dash-logo-black.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Dash logo/dash-logo-black.imageset/dash-logo-black@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Dash logo/dash-logo-black.imageset/dash-logo-black@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/image.import.private.key.large.imageset/import.private.key.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/image.import.private.key.large.imageset/import.private.key@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/image.import.private.key.large.imageset/import.private.key@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/zenledger_large.imageset/zenledger_large.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/zenledger_large.imageset/zenledger_large@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Illustration/zenledger_large.imageset/zenledger_large@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/Image.face.id.imageset/Layer 1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/Image.face.id.imageset/Layer 1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/Image.face.id.imageset/Layer 1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-advanced_security.imageset/image-menu-advanced_security.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-advanced_security.imageset/image-menu-advanced_security@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-advanced_security.imageset/image-menu-advanced_security@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-atm.imageset/image-menu-atm.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-atm.imageset/image-menu-atm@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-atm.imageset/image-menu-atm@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-autohide_balance.imageset/image-menu-autohide_balance.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-autohide_balance.imageset/image-menu-autohide_balance@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-autohide_balance.imageset/image-menu-autohide_balance@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-change_pin.imageset/image-menu-pin.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-change_pin.imageset/image-menu-pin@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-change_pin.imageset/image-menu-pin@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-enable_touch_id.imageset/image-menu-touch_id.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-enable_touch_id.imageset/image-menu-touch_id@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-enable_touch_id.imageset/image-menu-touch_id@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-face_id.imageset/image-menu-face_id.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-face_id.imageset/image-menu-face_id@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-face_id.imageset/image-menu-face_id@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-merchant.imageset/image-menu-merchant.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-merchant.imageset/image-menu-merchant@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-merchant.imageset/image-menu-merchant@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-recovery_phrase.imageset/image-menu-recovery_phrase.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-recovery_phrase.imageset/image-menu-recovery_phrase@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-recovery_phrase.imageset/image-menu-recovery_phrase@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-reset_wallet.imageset/image-menu-reset_wallet.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-reset_wallet.imageset/image-menu-reset_wallet@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-reset_wallet.imageset/image-menu-reset_wallet@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-staking.imageset/image-menu-staking.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-staking.imageset/image-menu-staking@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-staking.imageset/image-menu-staking@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.about.imageset/dash.logo.circle.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.about.imageset/dash.logo.circle@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.about.imageset/dash.logo.circle@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.advanced.security.imageset/advanced security.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.advanced.security.imageset/advanced security@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.advanced.security.imageset/advanced security@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.autohide.balance.imageset/eye.closed.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.autohide.balance.imageset/eye.closed@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.autohide.balance.imageset/eye.closed@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.buy.and.sell.imageset/buy.sell.dash.2.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.buy.and.sell.imageset/buy.sell.dash.2@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.buy.and.sell.imageset/buy.sell.dash.2@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.change.pin.imageset/Layer_1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.change.pin.imageset/Layer_1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.change.pin.imageset/Layer_1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/Layer_1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/Layer_1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/Layer_1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/mixing.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/mixing@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/mixing@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv-export.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv-export@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv-export@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv.export.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv.export@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/csv.export@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/cash.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/cash@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/cash@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/local.currency.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/local.currency@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/local.currency@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/Explore-Blue.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/Explore-Blue@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/Explore-Blue@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/explore-2.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/explore-2@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/explore-2@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/extend-public-key.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/extend-public-key@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/extend-public-key@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/public.key.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/public.key@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/public.key@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import-private-key.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import-private-key@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import-private-key@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import.private.key.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import.private.key@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/import.private.key@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/Layer_1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/Layer_1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/Layer_1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/masternode-keys.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/masternode-keys@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/masternode-keys@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/Layer_1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/Layer_1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/Layer_1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/network-monitor.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/network-monitor@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/network-monitor@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/Layer 1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/Layer 1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/Layer 1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/notification.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/notification@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/notification@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.recovery.phrase.imageset/Layer_1.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.recovery.phrase.imageset/Layer_1@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.recovery.phrase.imageset/Layer_1@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.rescan.imageset/rescan.blockchain.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.rescan.imageset/rescan.blockchain@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.rescan.imageset/rescan.blockchain@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.reset.wallet.imageset/reset wallet.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.reset.wallet.imageset/reset wallet@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.reset.wallet.imageset/reset wallet@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/Vector.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/Vector@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/Vector@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/security.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/security@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/security@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/Iconly_x2F_Bold_x2F_Setting.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/Iconly_x2F_Bold_x2F_Setting@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/Iconly_x2F_Bold_x2F_Setting@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/settings.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/settings@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/settings@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/Group.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/Group@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/Group@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/support.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/support@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/support@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/Group.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/Group@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/Group@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/tools.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/tools@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/tools@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.touch.id.imageset/fingerprint.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.touch.id.imageset/fingerprint@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/image.touch.id.imageset/fingerprint@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash_dark.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash_dark@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/menu_buySellDash_dark@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security_dark.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security_dark@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/menu_security_dark@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/levels.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/levels@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/levels@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/menu_settings.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/menu_settings@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/menu_settings@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_support.imageset/menu_support.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_support.imageset/menu_support@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_support.imageset/menu_support@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/menu_tools.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/menu_tools@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/menu_tools@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/tools.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/tools@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/tools@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-coinbase.imageset/menu-coinbase.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-coinbase.imageset/menu-coinbase@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-coinbase.imageset/menu-coinbase@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-topper.imageset/menu-topper.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-topper.imageset/menu-topper@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-topper.imageset/menu-topper@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-uphold.imageset/menu-uphold.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-uphold.imageset/menu-uphold@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/Menu/service-uphold.imageset/menu-uphold@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zen_ledger.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zen_ledger@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zen_ledger@3x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zenledger.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zenledger@2x.pngis excluded by!**/*.pngDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/zenledger@3x.pngis excluded by!**/*.png
📒 Files selected for processing (60)
DashSyncCurrentCommitDashWallet.xcodeproj/project.pbxprojDashWallet.xcodeproj/xcshareddata/xcschemes/dashwallet.xcschemeDashWallet/Resources/AppAssets.xcassets/Dash logo/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Dash logo/dash-logo-black.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Illustration/image.import.private.key.large.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Illustration/zenledger_large.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-advanced_security.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-atm.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-autohide_balance.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-change_pin.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-enable_touch_id.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-face_id.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-merchant.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-recovery_phrase.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-reset_wallet.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image-menu-staking.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.coinjoin.menu.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.csv.export.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.currency.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.explore.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.extend.public.key.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.import.private.key.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.masternode.keys.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.network.monitor.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.notifications.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.reset.wallet.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.security.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.settings.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.support.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.tools.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/image.touch.id.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/menu_support.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/service-coinbase.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/service-topper.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/Menu/service-uphold.imageset/Contents.jsonDashWallet/Resources/AppAssets.xcassets/zenledger.imageset/Contents.jsonDashWallet/Sources/UI/Buy Sell/BuySellPortalScreen.swiftDashWallet/Sources/UI/Buy Sell/BuySellPortalViewController.swiftDashWallet/Sources/UI/Buy Sell/Model/BuySellPortalModel.swiftDashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swiftDashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swiftDashWallet/Sources/UI/Main/MainTabbarController.swiftDashWallet/Sources/UI/Menu/Main/MainMenuViewController.swiftDashWallet/Sources/UI/Menu/Main/MainMenuViewModel.swiftDashWallet/Sources/UI/Menu/Security/SecurityMenuScreen.swiftDashWallet/Sources/UI/Menu/Security/SecurityMenuViewModel.swiftDashWallet/Sources/UI/Menu/Settings/SettingsMenuViewModel.swiftDashWallet/Sources/UI/Menu/Settings/SettingsScreen.swiftDashWallet/Sources/UI/Menu/Tools/ToolsMenuScreen.swiftDashWallet/Sources/UI/Menu/Tools/ToolsMenuViewModel.swiftDashWallet/Sources/UI/SwiftUI Components/Color+DWStyle.swiftDashWallet/Sources/UI/SwiftUI Components/MenuItem.swiftDashWallet/Sources/UI/SwiftUI Components/TopIntro.swiftShared/Resources/SharedAssets.xcassets/Colors/BackgroundColor.colorset/Contents.jsonShared/Resources/SharedAssets.xcassets/Colors/Black800.colorset/Contents.json
💤 Files with no reviewable changes (7)
- DashWallet/Resources/AppAssets.xcassets/Menu/menu_support.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/menu_buySellDash.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/menu_security.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/image.reset.wallet.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/menu_settings.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/image.touch.id.imageset/Contents.json
- DashWallet/Resources/AppAssets.xcassets/Menu/menu_tools.imageset/Contents.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
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)
DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift (1)
514-557: 🛠️ Refactor suggestion | 🟠 MajorRemove dead
ExploreViewControllerDelegateconformance and unused methods fromDelegateInternal.
showExplore()now usesExploreMenuScreenwith closure-based callbacks instead ofExploreViewController, making theExploreViewControllerDelegateconformance onDelegateInternaldead code. Remove the protocol conformance and the three forwarding methods (exploreViewControllerShowSendPayment,exploreViewControllerShowReceivePayment,exploreViewControllerShowGiftCard) at lines 547–557. Additionally, remove theExploreViewControllerDelegateprotocol definition and the@objc weak var delegateproperty fromExploreViewControlleras they are no longer used.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift` around lines 514 - 557, Remove dead explore delegation: delete ExploreViewControllerDelegate conformance from the DelegateInternal class and remove the three unused forwarding methods exploreViewControllerShowSendPayment(_:), exploreViewControllerShowReceivePayment(_:), and exploreViewControllerShowGiftCard(_:txId:) from DelegateInternal; also delete the ExploreViewControllerDelegate protocol definition and the now-unused `@objc` weak var delegate property on ExploreViewController, since showExplore() now uses ExploreMenuScreen closure callbacks instead of ExploreViewController delegation.
♻️ Duplicate comments (1)
DashWallet/Sources/UI/Main/MainTabbarController.swift (1)
239-239:⚠️ Potential issue | 🟠 MajorWrap
ExploreMenuScreenin a thin hosting controller subclass.Pushing a bare
UIHostingController(rootView: exploreScreen)intoBaseNavigationControllerbypasses the navigation-bar handling performed byBaseNavigationController.willShow, which only applies to controllers conforming toNavigationBarDisplayable/NavigationStackControllable. The same pattern is already followed elsewhere in this repo (e.g.,SelectCoinHostingController,MayaPortalViewController).Based on learnings: "In the DashWallet iOS project, when pushing SwiftUI views into BaseNavigationController, wrap the SwiftUI view in a thin UIViewController subclass … instead of pushing a bare UIHostingController."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Main/MainTabbarController.swift` at line 239, Replace the bare UIHostingController(rootView: exploreScreen) with a thin hosting-controller subclass (e.g., ExploreMenuHostingController) that wraps the ExploreMenuScreen and conforms to the navigation protocols used by BaseNavigationController (NavigationBarDisplayable / NavigationStackControllable) so BaseNavigationController.willShow can apply its navigation-bar handling; follow the existing pattern used by SelectCoinHostingController and MayaPortalViewController by creating ExploreMenuHostingController that hosts the SwiftUI view and use nvc.viewControllers = [ExploreMenuHostingController(rootView: exploreScreen)].
🧹 Nitpick comments (7)
DashWallet/Sources/UI/SwiftUI Components/MenuItem.swift (1)
36-36: Minor: SwiftLintimplicit_optional_initializationon new properties.
trailingView: AnyView? = nil(and the existing siblings flagged by SwiftLint on lines 25-39) should drop the explicit= nilto comply with the configured rule. Since you’re already touching this declaration list, a small cleanup here would silence the new warning introduced on line 36 without affecting behavior.🛠️ Suggested change
- var trailingView: AnyView? = nil + var trailingView: AnyView?As per coding guidelines: "Use SwiftFormat and SwiftLint for Swift code formatting and linting as configured in .swiftformat and .swiftlint.yml files."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/SwiftUI` Components/MenuItem.swift at line 36, Remove explicit "= nil" initializers from optional stored properties in the MenuItem declaration (e.g., trailingView: AnyView?) to satisfy SwiftLint's implicit_optional_initialization rule; locate the optional properties in MenuItem.swift (the trailingView property and the other optional siblings in the same declaration block) and change declarations like "trailingView: AnyView? = nil" to "trailingView: AnyView?" without altering types or behavior.DashWallet/Sources/UI/Buy Sell/BuySellPortalViewController.swift (1)
147-150: Preferstaticoverclassin a final class.Since the class is
final, the method cannot be overridden andstaticmore accurately conveys intent (and silences SwiftLint’sstatic_over_final_class).♻️ Proposed fix
- `@objc` - class func controller() -> BuySellPortalViewController { - BuySellPortalViewController() - } + `@objc` + static func controller() -> BuySellPortalViewController { + BuySellPortalViewController() + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalViewController.swift around lines 147 - 150, The factory method declaration uses `class func controller()` inside the final `BuySellPortalViewController` — change it to `static func controller()` to reflect that it cannot be overridden and satisfy SwiftLint's `static_over_final_class`; update the method signature in the `BuySellPortalViewController` type (the `controller()` factory method) accordingly while leaving its implementation `BuySellPortalViewController()` unchanged.DashWallet/Sources/UI/Buy Sell/BuySellPortalScreen.swift (1)
32-32: Minor: place@Environment(\.colorScheme)on its own line.SwiftLint’s
attributesrule flags attributes with arguments on the same line as the declaration.♻️ Proposed fix
- `@Environment`(\.colorScheme) private var colorScheme + `@Environment`(\.colorScheme) + private var colorSchemeAs per coding guidelines: "Use SwiftFormat and SwiftLint for Swift code formatting and linting as configured in .swiftformat and .swiftlint.yml files."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalScreen.swift at line 32, Move the attribute onto its own line so it doesn't share the line with the declaration: take the current `@Environment(\.colorScheme) private var colorScheme` and split it into an attribute line (`@Environment(\.colorScheme)`) above the property declaration (`private var colorScheme`) to satisfy SwiftLint's `attributes` rule and match project formatting for the `colorScheme` environment property.DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift (2)
197-198:LazyVStackwith a single-childTopIntro+ conditional content.Switching the outer stack to
LazyVStackchanges how SwiftUI measures/layouts the content (subviews are materialized lazily on scroll). Since this stack is already inside aScrollViewand the content is small/finite,VStackis typically sufficient and avoids subtle layout quirks (e.g., appearance animations firing on scroll,Spacerinteractions). If the intent is just to defer the credits-warning overlay materialization, consider keepingVStackfor the menu content and lazily loading only the heavy parts.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift` around lines 197 - 198, The Menu view uses LazyVStack for the outer container (wrapping TopIntro and conditional content) inside a ScrollView which can cause lazy materialization/layout quirks; change the outer LazyVStack to a regular VStack for the main menu content (e.g., replace LazyVStack around TopIntro and related menu items) and keep lazy loading only for heavy/optional parts (like the credits/warning overlay or any heavy subviews) by wrapping those specific subviews in LazyVStack or on-demand views instead; update references to LazyVStack in MainMenuViewController (around TopIntro) accordingly.
461-461: Inconsistent indentation for#if DASHPAY.This
#if DASHPAY(and its matching#endifon Line 509) sits at column 0, while the other conditional blocks in this struct (e.g., Lines 200, 274, 308, 346) are indented with the surrounding code. Align it with the rest of the file for consistency.♻️ Proposed fix
-#if DASHPAY + `#if` DASHPAY private func showInvite() {And match the
#endifat Line 509.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift` at line 461, The preprocessor directive `#if DASHPAY` and its matching `#endif` in MainMenuViewController.swift are at column 0 while other conditional blocks in the same struct are indented; move/indent the `#if DASHPAY` and corresponding `#endif` to match the surrounding code indentation (same level as the other `#if` blocks around lines with existing conditionals) so the conditional sits within the struct's indentation and aligns with the surrounding code.DashWallet/Sources/UI/SwiftUI Components/TopIntro.swift (1)
36-40: Asymmetric horizontal padding may truncate long localized subtitles.The trailing padding (60) is 3× the leading padding (20), leaving a narrow content area on the right. Longer localized title/subtitle strings (e.g., German/French for "Find merchants that accept Dash…") could wrap awkwardly or look unbalanced. Consider whether this asymmetry is intentional (e.g., to leave room for a visual element) or if it should be symmetric.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/SwiftUI` Components/TopIntro.swift around lines 36 - 40, The asymmetric horizontal padding in the TopIntro view (.padding(.leading, 20) vs .padding(.trailing, 60)) can cause long localized subtitles to truncate or wrap awkwardly; update the view modifiers in TopIntro to use symmetric horizontal padding (e.g., replace the separate leading/trailing pads with a single .padding(.horizontal, 20) or reduce .padding(.trailing) to 20) or, if the extra trailing space is intentional for a visual element, add a clear comment and reserve space responsively (e.g., using layout/Spacer or GeometryReader) so localized strings aren’t truncated.DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift (1)
144-155: Duplicated “show MerchantTypesDialog once” logic withExploreViewController.This is a near-verbatim copy of
ExploreViewController.showWhereToSpendViewController()(Lines 164–175 ofExploreViewController.swift). If the UX rule changes (e.g., different detent, reset on version upgrade), both sites will need to be kept in sync. Consider extracting this to a small helper onMerchantTypesDialogor a free function, e.g.MerchantTypesDialog.presentIfNeeded(on:onContinue:).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@DashWallet/Sources/UI/Explore` Dash/ExploreMenuScreen.swift around lines 144 - 155, The showWhereToSpend duplication should be extracted into a single helper to avoid drifting UX behavior: add a static helper like MerchantTypesDialog.presentIfNeeded(on: UIViewController, detentHeight: CGFloat = 640, onContinue: `@escaping` () -> Void) (or a free function) that checks UserDefaults with kMerchantTypesShown, builds the UIHostingController(rootView: MerchantTypesDialog { ... }), calls hostingController.setDetent(detentHeight), presents it on the provided vc, and sets UserDefaults when the dialog continues; then replace the body of ExploreMenuScreen.showWhereToSpend and ExploreViewController.showWhereToSpendViewController with a single call to that new helper (passing vc, detent, and showMerchants as onContinue).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@DashWallet/Sources/UI/Explore` Dash/ExploreMenuScreen.swift:
- Around line 22-45: ExploreMenuScreen currently holds a strong reference to the
UINavigationController via the stored property vc which creates a retain cycle
(nvc → UIHostingController → rootView → vc). Replace the strong reference by
wrapping the navigation controller in a weak-holder class (e.g. a small
WeakBox<T: AnyObject> with a weak var value: T?) and change the stored property
type from UINavigationController to WeakBox<UINavigationController> (or accept a
UINavigationController in init and store WeakBox(nvc)); update usages to access
vc.value to push/present, or alternatively remove vc entirely and pass only
navigation action closures
(onShowSendPayment/onShowReceivePayment/onShowGiftCard) as done elsewhere
(adjust MainTabbarController.configureControllers(),
MainMenuViewController.showExplore(), and HomeViewController+Shortcuts.swift to
construct the view with the new API).
- Line 185: The division operators in ExploreMenuScreen.systemGreen (private
static let systemGreen) lack surrounding whitespace; update the numeric
expressions to use spaces (e.g., 98 / 255, 182 / 255, 125 / 255) so they comply
with SwiftLint operator_usage_whitespace, then run the project's
SwiftFormat/SwiftLint formatter to apply and verify the change.
- Around line 18-21: Reorder and tidy the import block in
ExploreMenuScreen.swift: place import SwiftUI before import UIKit (to satisfy
SwiftLint sorted_imports) and remove the stray blank line after the imports so
the top-level declaration immediately follows the imports.
- Around line 184-207: The APY formatter in CrowdNodeAPYBadge currently sets
NumberFormatter.multiplier = 1 which causes a percent-style formatter to
multiply an already-percent value (CrowdNode.shared.crowdnodeAPY) again; change
the multiplier to 0.01 inside the apy computed property so the percent value
(e.g., 7.5) is converted to decimal (0.075) before formatting; update the same
change in the analogous formatter in CrowdNodeAPYView (the NumberFormatter setup
where multiplier is set) to ensure consistent percent display.
In `@DashWallet/Sources/UI/Main/MainTabbarController.swift`:
- Around line 228-239: The code instantiates BaseNavigationController() which
bypasses the customizations in
BaseNavigationController.init(rootViewController:) (the
interactivePopGestureRecognizer delegate and tintColor). Replace the call to
BaseNavigationController() so the navigation controller is created with the
proper initializer: either call BaseNavigationController(rootViewController:
UIHostingController(rootView: exploreScreen)) or add and use a convenience
BaseNavigationController initializer that accepts the SwiftUI view (or a
UIViewController) and performs the hosting-controller wrap plus the existing
setup; ensure ExploreMenuScreen is wrapped into a UIHostingController and passed
into BaseNavigationController's init(rootViewController:) so the gesture
delegate and navigationBar.tintColor are applied.
---
Outside diff comments:
In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift`:
- Around line 514-557: Remove dead explore delegation: delete
ExploreViewControllerDelegate conformance from the DelegateInternal class and
remove the three unused forwarding methods
exploreViewControllerShowSendPayment(_:),
exploreViewControllerShowReceivePayment(_:), and
exploreViewControllerShowGiftCard(_:txId:) from DelegateInternal; also delete
the ExploreViewControllerDelegate protocol definition and the now-unused `@objc`
weak var delegate property on ExploreViewController, since showExplore() now
uses ExploreMenuScreen closure callbacks instead of ExploreViewController
delegation.
---
Duplicate comments:
In `@DashWallet/Sources/UI/Main/MainTabbarController.swift`:
- Line 239: Replace the bare UIHostingController(rootView: exploreScreen) with a
thin hosting-controller subclass (e.g., ExploreMenuHostingController) that wraps
the ExploreMenuScreen and conforms to the navigation protocols used by
BaseNavigationController (NavigationBarDisplayable /
NavigationStackControllable) so BaseNavigationController.willShow can apply its
navigation-bar handling; follow the existing pattern used by
SelectCoinHostingController and MayaPortalViewController by creating
ExploreMenuHostingController that hosts the SwiftUI view and use
nvc.viewControllers = [ExploreMenuHostingController(rootView: exploreScreen)].
---
Nitpick comments:
In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalScreen.swift:
- Line 32: Move the attribute onto its own line so it doesn't share the line
with the declaration: take the current `@Environment(\.colorScheme) private var
colorScheme` and split it into an attribute line (`@Environment(\.colorScheme)`)
above the property declaration (`private var colorScheme`) to satisfy
SwiftLint's `attributes` rule and match project formatting for the `colorScheme`
environment property.
In `@DashWallet/Sources/UI/Buy` Sell/BuySellPortalViewController.swift:
- Around line 147-150: The factory method declaration uses `class func
controller()` inside the final `BuySellPortalViewController` — change it to
`static func controller()` to reflect that it cannot be overridden and satisfy
SwiftLint's `static_over_final_class`; update the method signature in the
`BuySellPortalViewController` type (the `controller()` factory method)
accordingly while leaving its implementation `BuySellPortalViewController()`
unchanged.
In `@DashWallet/Sources/UI/Explore` Dash/ExploreMenuScreen.swift:
- Around line 144-155: The showWhereToSpend duplication should be extracted into
a single helper to avoid drifting UX behavior: add a static helper like
MerchantTypesDialog.presentIfNeeded(on: UIViewController, detentHeight: CGFloat
= 640, onContinue: `@escaping` () -> Void) (or a free function) that checks
UserDefaults with kMerchantTypesShown, builds the UIHostingController(rootView:
MerchantTypesDialog { ... }), calls hostingController.setDetent(detentHeight),
presents it on the provided vc, and sets UserDefaults when the dialog continues;
then replace the body of ExploreMenuScreen.showWhereToSpend and
ExploreViewController.showWhereToSpendViewController with a single call to that
new helper (passing vc, detent, and showMerchants as onContinue).
In `@DashWallet/Sources/UI/Menu/Main/MainMenuViewController.swift`:
- Around line 197-198: The Menu view uses LazyVStack for the outer container
(wrapping TopIntro and conditional content) inside a ScrollView which can cause
lazy materialization/layout quirks; change the outer LazyVStack to a regular
VStack for the main menu content (e.g., replace LazyVStack around TopIntro and
related menu items) and keep lazy loading only for heavy/optional parts (like
the credits/warning overlay or any heavy subviews) by wrapping those specific
subviews in LazyVStack or on-demand views instead; update references to
LazyVStack in MainMenuViewController (around TopIntro) accordingly.
- Line 461: The preprocessor directive `#if DASHPAY` and its matching `#endif`
in MainMenuViewController.swift are at column 0 while other conditional blocks
in the same struct are indented; move/indent the `#if DASHPAY` and corresponding
`#endif` to match the surrounding code indentation (same level as the other
`#if` blocks around lines with existing conditionals) so the conditional sits
within the struct's indentation and aligns with the surrounding code.
In `@DashWallet/Sources/UI/SwiftUI` Components/MenuItem.swift:
- Line 36: Remove explicit "= nil" initializers from optional stored properties
in the MenuItem declaration (e.g., trailingView: AnyView?) to satisfy
SwiftLint's implicit_optional_initialization rule; locate the optional
properties in MenuItem.swift (the trailingView property and the other optional
siblings in the same declaration block) and change declarations like
"trailingView: AnyView? = nil" to "trailingView: AnyView?" without altering
types or behavior.
In `@DashWallet/Sources/UI/SwiftUI` Components/TopIntro.swift:
- Around line 36-40: The asymmetric horizontal padding in the TopIntro view
(.padding(.leading, 20) vs .padding(.trailing, 60)) can cause long localized
subtitles to truncate or wrap awkwardly; update the view modifiers in TopIntro
to use symmetric horizontal padding (e.g., replace the separate leading/trailing
pads with a single .padding(.horizontal, 20) or reduce .padding(.trailing) to
20) or, if the extra trailing space is intentional for a visual element, add a
clear comment and reserve space responsively (e.g., using layout/Spacer or
GeometryReader) so localized strings aren’t truncated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7a0d60fc-e05a-43d9-8373-a9acd8d69db3
📒 Files selected for processing (10)
DashWallet/Sources/UI/Buy Sell/BuySellPortalScreen.swiftDashWallet/Sources/UI/Buy Sell/BuySellPortalViewController.swiftDashWallet/Sources/UI/Buy Sell/Model/BuySellPortalModel.swiftDashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swiftDashWallet/Sources/UI/Explore Dash/ExploreViewController.swiftDashWallet/Sources/UI/Main/MainTabbarController.swiftDashWallet/Sources/UI/Menu/Main/MainMenuViewController.swiftDashWallet/Sources/UI/SwiftUI Components/MenuItem.swiftDashWallet/Sources/UI/SwiftUI Components/TopIntro.swiftDashWallet/en.lproj/Localizable.strings
✅ Files skipped from review due to trivial changes (1)
- DashWallet/en.lproj/Localizable.strings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gation
Issue being fixed or feature implemented
What was done?
How Has This Been Tested?
Breaking Changes
Checklist:
For repository code-owners and collaborators only
Summary by CodeRabbit
New Features
UI Improvements
Assets & Localization