Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
20cb477
fix: allow the payment button on the nav bar to be clicked
HashEngineering Apr 10, 2026
19a5d88
fix(dashpay): fix compile issues in HomeViewController+Shortcuts
HashEngineering Apr 10, 2026
c268c59
fix: simplify the bottom nav bar, specifically the payments button
HashEngineering Apr 14, 2026
ca983d8
fix: fix padding on Shortcut bar on home screen
HashEngineering Apr 14, 2026
b5ae4eb
fix: update scan button to blue for dark mode
HashEngineering Apr 14, 2026
405dfc9
fix: center back arrow in back buttons
HashEngineering Apr 14, 2026
cfef5e1
fix: prevent crash if not FaceID nor TouchID
HashEngineering Apr 14, 2026
f870628
fix: remove invisible button on BuySellPortal
HashEngineering Apr 14, 2026
a7d6776
feat(search): add SwiftUI search bar styles and assets
jeanpierreroma Apr 17, 2026
3031917
fix(search): adjust field layout and related color assets
jeanpierreroma Apr 17, 2026
37ebbca
feat(settings): add SwiftUI local currency selector
jeanpierreroma Apr 17, 2026
c85a865
refactor(local-currency): extract CurrencyItem and debounce filtering
jeanpierreroma Apr 20, 2026
c57de5e
fix(previews): enable local currency SwiftUI previews
jeanpierreroma Apr 20, 2026
a74a184
ci: enforce Xcode 26.x for release archive pipeline
jeanpierreroma Apr 20, 2026
b12f1c9
ci: enable release archive workflow on PR to master
jeanpierreroma Apr 20, 2026
6543b2d
Merge branch 'master' of https://github.com/dashpay/dashwallet-ios in…
HashEngineering Apr 24, 2026
67384d0
chore: remove release-code26.yml
HashEngineering Apr 24, 2026
d64385a
chore: remove unused field in MainTabbarController
HashEngineering Apr 24, 2026
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
71 changes: 70 additions & 1 deletion DashWallet.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = "en"
Expand Down
6 changes: 6 additions & 0 deletions DashWallet/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ - (void)registerForPushNotifications {
#pragma mark - UIApplicationDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {
#if DEBUG
if ([NSProcessInfo.processInfo.environment[@"XCODE_RUNNING_FOR_PREVIEWS"] isEqualToString:@"1"]) {
return YES;
}
#endif /* DEBUG */

#if FRESH_INSTALL
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
Expand Down
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 @@ -181,7 +181,8 @@ extension HomeViewController: DWLocalCurrencyViewControllerDelegate {

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 @@ -310,3 +311,14 @@ extension HomeViewController: DWLocalCurrencyViewControllerDelegate {
}

}
#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

Comment thread
HashEngineering marked this conversation as resolved.
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: 39 additions & 53 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?
#endif
Expand All @@ -93,8 +89,6 @@ class MainTabbarController: UITabBarController {
@objc
weak var wipeDelegate: DWWipeDelegate?

private var paymentButton: PaymentButton!

@objc
var isDemoMode = false

Expand All @@ -104,7 +98,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 @@ -145,35 +139,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 @@ -211,13 +185,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)
Comment thread
HashEngineering marked this conversation as resolved.

#if DASHPAY
if identity != nil {
Expand Down Expand Up @@ -263,25 +239,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)
}
Comment thread
HashEngineering marked this conversation as resolved.

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

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

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

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

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

let receiveModel = DWReceiveModel()
let payModel = DWPayModel()
Expand Down Expand Up @@ -434,7 +415,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
Loading
Loading