Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions DashWallet/Sources/UI/Buy Sell/BuySellPortal.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,6 @@
<constraint firstAttribute="bottom" secondItem="qd5-Z5-oBS" secondAttribute="bottom" id="pMR-5x-rbt"/>
</constraints>
</view>
<barButtonItem key="rightBarButtonItem" enabled="NO" id="jKH-G2-hOt">
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
Expand Down
14 changes: 13 additions & 1 deletion DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ extension HomeViewController: DWLocalCurrencyViewControllerDelegate, ExploreView

private func showSendToContact() {
#if DASHPAY
let controller = DWContactsViewController()
let controller = DWContactsViewController(payModel: payModel, dataProvider: dataProvider)
controller.intent = .payToSelector
controller.payDelegate = self
let navigationController = BaseNavigationController(rootViewController: controller)
present(navigationController, animated: true, completion: nil)
Expand Down Expand Up @@ -311,3 +312,14 @@ extension HomeViewController: DWLocalCurrencyViewControllerDelegate, ExploreView
showGiftCardDetails(txId: txId)
}
}
#if DASHPAY
// MARK: DWContactsViewControllerPayDelegate
extension HomeViewController: DWContactsViewControllerPayDelegate {
func contactsViewController(_ controller: DWContactsViewController, payTo item: DWDPBasicUserItem) {
dismiss(animated: true) { [weak self] in
self?.performPay(toUser: item)
}
}
}
#endif

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix trailing newline lint warning.

SwiftLint reports the file ending does not satisfy the single trailing newline rule.

✂️ Minimal formatting fix
-#endif
-
+#endif

As per coding guidelines: **/*.swift: Use SwiftFormat and SwiftLint for Swift code formatting and linting as configured in .swiftformat and .swiftlint.yml files.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`#endif`
🧰 Tools
🪛 SwiftLint (0.63.2)

[Warning] 325-325: Files should have a single trailing newline

(trailing_newline)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@DashWallet/Sources/UI/Home/HomeViewController`+Shortcuts.swift at line 325,
The file HomeViewController+Shortcuts.swift is missing a single trailing newline
at EOF which triggers SwiftLint; open the file
(HomeViewController+Shortcuts.swift) and ensure the file ends with exactly one
newline character (add a single trailing newline after the last line) so it
conforms to the single trailing newline rule used by SwiftLint/SwiftFormat.

Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ protocol ShortcutsViewDelegate: AnyObject {
// MARK: - ShortcutsView

class ShortcutsView: UIView {
private static let verticalPadding: CGFloat = 8.0

private var cancellableBag = Set<AnyCancellable>()
private let viewModel: HomeViewModel
private var lastLayoutWidth: CGFloat = 0
Expand Down Expand Up @@ -140,7 +142,7 @@ class ShortcutsView: UIView {
var cellSize = cellSize(for: contentSizeCategory, viewWidth: width)
cellSize.height = ceil(cellSize.height) // This fixes the autolayout issue when the size of the cell is higher than the collection view itself

collectionViewHeightConstraint.constant = cellSize.height
collectionViewHeightConstraint.constant = cellSize.height + ShortcutsView.verticalPadding * 2
setNeedsUpdateConstraints()

if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
Expand Down Expand Up @@ -212,7 +214,7 @@ extension ShortcutsView: UICollectionViewDataSource, UICollectionViewDelegate, U
let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
var inset = (collectionView.bounds.size.width - (cellCount * cellWidth) - ((cellCount - 1) * cellSpacing)) * 0.5
inset = max(inset, 0.0)
return UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset)
return UIEdgeInsets(top: ShortcutsView.verticalPadding, left: inset, bottom: ShortcutsView.verticalPadding, right: inset)
}
}

Expand Down
92 changes: 40 additions & 52 deletions DashWallet/Sources/UI/Main/MainTabbarController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ private enum MainTabbarTabs: Int, CaseIterable {
}

extension MainTabbarTabs {
var isEmpty: Bool {
self == .payment
}

var icon: UIImage {
let name: String

Expand All @@ -42,7 +38,7 @@ extension MainTabbarTabs {
case .contacts:
name = "tabbar_contacts_icon"
case .payment:
return UIImage()
name = "tabbar_pay_button"
case .explore:
name = "tabbar_discover_icon"
case .more:
Expand All @@ -51,7 +47,7 @@ extension MainTabbarTabs {

return UIImage(named: name)!.withRenderingMode(.alwaysOriginal)
}

var selectedIcon: UIImage {
let name: String

Expand All @@ -61,7 +57,7 @@ extension MainTabbarTabs {
case .contacts:
name = "tabbar_contacts_selected"
case .payment:
return UIImage()
name = "tabbar_pay_button"
case .explore:
name = "tabbar_discover_selected"
case .more:
Expand All @@ -84,7 +80,7 @@ class MainTabbarController: UITabBarController {

weak var homeController: HomeViewController?
weak var menuNavigationController: MainMenuViewController?

#if DASHPAY
weak var contactsNavigationController: DWRootContactsViewController?
weak var exploreNavigationController: ExploreViewController?
Expand All @@ -94,7 +90,7 @@ class MainTabbarController: UITabBarController {
@objc
weak var wipeDelegate: DWWipeDelegate?

private var paymentButton: PaymentButton!
private var paymentIsOpened = false
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if paymentIsOpened is read anywhere in the codebase
rg -n 'paymentIsOpened' --type swift -C2

Repository: dashpay/dashwallet-ios

Length of output: 1829


Remove the unused paymentIsOpened property.

This property is assigned in closePayments(), paymentsViewControllerWantsToImportPrivateKey(), and showPaymentsController() but never read. It appears to be dead code from the refactoring that replaced PaymentButton with the EmptyController interceptor pattern.

🤖 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 93, Remove the
dead stored property paymentIsOpened from MainTabbarController: delete the
declaration `private var paymentIsOpened = false` and remove any assignments to
it in closePayments(), paymentsViewControllerWantsToImportPrivateKey(), and
showPaymentsController(); keep the existing flow implemented by the
EmptyController interceptor/PaymentButton refactor and ensure no other code
references paymentIsOpened (search for the symbol and remove or adapt any
leftover uses).


@objc
var isDemoMode = false
Expand All @@ -105,7 +101,7 @@ class MainTabbarController: UITabBarController {
// TODO: Move it out from here and initialize the model inside home view controller
@objc
var homeModel: DWHomeProtocol!

#if DASHPAY
// TODO: MOCK_DASHPAY remove when not mocked
private var blockchainIdentity: DSBlockchainIdentity? {
Expand Down Expand Up @@ -146,35 +142,15 @@ class MainTabbarController: UITabBarController {
fatalError("init(coder:) has not been implemented")
}

// MARK: Actions

@objc
private func paymentButtonAction() {
showPaymentsController(withActivePage: .none)
}

// MARK: Life Cycle

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

tabBar.addSubview(paymentButton)
}

override func viewDidLoad() {
super.viewDidLoad()

delegate = self
configureHierarchy()
tabBar.barTintColor = .dw_background()
setupRatesErrorHandling()
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

// Add Payment Button again to make sure it's at the top
tabBar.addSubview(paymentButton)
}
}

// MARK: - Private
Expand Down Expand Up @@ -212,13 +188,15 @@ extension MainTabbarController {
}
#endif

// Payment
item = UITabBarItem(title: "", image: UIImage(), tag: 2)
// Payment (tapping this tab opens the payment modal instead of switching tabs)
let paymentImage = Self.makePaymentTabImage()
item = UITabBarItem(title: nil, image: paymentImage, selectedImage: paymentImage)
item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
item.accessibilityIdentifier = "tabbar_payments_button"

let vc = EmptyController()
vc.tabBarItem = item
viewControllers.append(vc)
let paymentVC = EmptyController()
paymentVC.tabBarItem = item
viewControllers.append(paymentVC)

#if DASHPAY
if identity != nil {
Expand Down Expand Up @@ -256,25 +234,30 @@ extension MainTabbarController {
self.viewControllers = viewControllers
}

private func configureHierarchy() {
paymentButton = PaymentButton()
paymentButton.translatesAutoresizingMaskIntoConstraints = false
paymentButton.addTarget(self, action: #selector(paymentButtonAction), for: .touchUpInside)
tabBar.addSubview(paymentButton)
/// Creates a tab bar image with a blue circle background and the payment icon centered on top.
private static func makePaymentTabImage() -> UIImage {
let size: CGFloat = 47
let rect = CGRect(x: 0, y: 0, width: size, height: size)

NSLayoutConstraint.activate([
paymentButton.centerXAnchor.constraint(equalTo: tabBar.centerXAnchor),
paymentButton.topAnchor.constraint(equalTo: tabBar.topAnchor, constant: UIDevice.hasHomeIndicator ? 4 : 1),
let renderer = UIGraphicsImageRenderer(size: rect.size)
let image = renderer.image { context in
// Draw blue circle background
UIColor.dw_dashBlue().setFill()
UIBezierPath(ovalIn: rect).fill()

paymentButton.widthAnchor.constraint(equalToConstant: PaymentButton.kCenterCircleSize),
paymentButton.heightAnchor.constraint(equalToConstant: PaymentButton.kCenterCircleSize),
])
// Draw icon centered
if let icon = UIImage(named: "tabbar_pay_button") {
let iconSize = CGSize(width: 22, height: 22)
let iconOrigin = CGPoint(x: (size - iconSize.width) / 2, y: (size - iconSize.height) / 2)
icon.draw(in: CGRect(origin: iconOrigin, size: iconSize))
}
}

tabBar.barTintColor = .dw_background()
return image.withRenderingMode(.alwaysOriginal)
}

private func closePayments(completion: (() -> Void)? = nil) {
paymentButton.isOpened = false
paymentIsOpened = false

guard let top = selectedViewController?.topController(),
top != selectedViewController
Expand Down Expand Up @@ -378,7 +361,7 @@ extension MainTabbarController: PaymentsViewControllerDelegate {
}

func paymentsViewControllerWantsToImportPrivateKey(_ controller: PaymentsViewController) {
paymentButton.isOpened = false
paymentIsOpened = false

controller.dismiss(animated: true) {
self.performScanQRCodeAction()
Expand All @@ -398,7 +381,7 @@ extension MainTabbarController: HomeViewControllerDelegate {
}

func showPaymentsController(withActivePage pageIndex: PaymentsViewControllerState) {
paymentButton.isOpened = true
paymentIsOpened = true

let receiveModel = DWReceiveModel()
let payModel = DWPayModel()
Expand Down Expand Up @@ -427,7 +410,12 @@ extension MainTabbarController: HomeViewControllerDelegate {

extension MainTabbarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
!(viewController is EmptyController)
if viewController is EmptyController {
// Intercept the payment tab tap — show the payment modal instead of switching tabs
showPaymentsController(withActivePage: .none)
return false
}
return true
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ - (NSAttributedString *)currentSpendingConfirmationDescriptionWithFont:(UIFont *
else if (self.hasFaceID) {
string = NSLocalizedString(@"You can authenticate with Face ID for payments below", nil);
}
NSParameterAssert(string);
else {
string = NSLocalizedString(@"You can authenticate with biometrics for payments below", nil);
}

string = [string stringByAppendingString:@" "];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ extension BaseNavigationController: UINavigationControllerDelegate {
backButton.frame = .init(x: 0, y: 0, width: 30, height: 30)
backButton.setImage(UIImage(systemName: "arrow.backward"), for: .normal)
backButton.tintColor = backButtonTintColor
backButton.imageEdgeInsets = .init(top: 0, left: -10, bottom: 0, right: 0)
backButton.addTarget(self, action: #selector(backButtonAction), for: .touchUpInside)
let item = UIBarButtonItem(customView: backButton)

Expand Down
Loading