-
Notifications
You must be signed in to change notification settings - Fork 24
fix: support iOS 26 #764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
fix: support iOS 26 #764
Changes from 14 commits
20cb477
19a5d88
c268c59
ca983d8
b5ae4eb
405dfc9
cfef5e1
f870628
a7d6776
3031917
37ebbca
c85a865
c57de5e
a74a184
b12f1c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| name: Release Archive (Xcode 26.x) | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| push: | ||
| branches: | ||
| - release/* | ||
| - release/** | ||
|
|
||
| jobs: | ||
| archive: | ||
| name: Archive Build | ||
| runs-on: macos-latest | ||
| timeout-minutes: 90 | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Select Xcode 26.x | ||
| uses: maxim-lobanov/setup-xcode@v1 | ||
| with: | ||
| xcode-version: "26.x" | ||
|
|
||
| - name: Verify Xcode version | ||
| run: | | ||
| mkdir -p build | ||
| xcodebuild -version | tee build/xcode-version.txt | ||
| if ! grep -Eq '^Xcode 26\.' build/xcode-version.txt; then | ||
| echo "Expected Xcode 26.x but got:" | ||
| cat build/xcode-version.txt | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Setup CocoaPods | ||
| uses: maxim-lobanov/setup-cocoapods@v1 | ||
| with: | ||
| version: "1.15.2" | ||
|
Comment on lines
+37
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: The GitHub Action maxim-lobanov/setup-cocoapods sets up a specific version of CocoaPods in GitHub Actions workflows, primarily for macOS and Ubuntu runners. It supports specifying the version directly via the 'version' input (e.g., 'latest', '1.9.0') or dynamically parsing it from a Podfile.lock file using the 'podfile-path' input. Only one of these inputs should be used at a time. Key details: - Repository: https://github.com/maxim-lobanov/setup-cocoapods (31 stars, MIT license) - Latest release: v1.4.0 (November 27, 2023) - Last commit: November 27, 2023 (no updates since, as of 2026-04-20) - Available on GitHub Marketplace: https://github.com/marketplace/actions/setup-cocoapods Example usage: - name: Setup CocoaPods uses: maxim-lobanov/setup-cocoapods@v1 with: version: 1.9.0 or - name: Setup CocoaPods from Podfile.lock uses: maxim-lobanov/setup-cocoapods@v1 with: podfile-path: Example/Podfile.lock Status and considerations: - Open issues: 7 (e.g., caching requests, permission errors on Linux) - Security: StepSecurity rates it 2/10 due to 17 detected vulnerabilities in dependencies, no branch protection, no security policy. No published GitHub security advisories. - Maintenance: Inactive since late 2023 (0 commits in last 90 days per sources). - Alternative: step-security/setup-cocoapods (forked March 2026, actively maintained as a secure drop-in replacement, last push April 2026). Note: Not certified by GitHub; third-party action. Citations:
🏁 Script executed: #!/bin/bash
# Confirm the action is referenced consistently and check if resolvable via the GitHub API.
gh api repos/maxim-lobanov/setup-cocoapods 2>&1 | head -20Repository: dashpay/dashwallet-ios Length of output: 5922 Consider using the actively maintained The 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Ensure fastlane is available | ||
| run: | | ||
| if ! command -v fastlane >/dev/null 2>&1; then | ||
| gem install fastlane -N | ||
| fi | ||
| fastlane --version | ||
|
|
||
| - name: Install pods | ||
| run: pod install --repo-update | ||
|
|
||
| - name: Build release archive | ||
| run: fastlane ios release_archive_ci | ||
|
|
||
| - name: Upload build logs | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: release-xcode26-logs-${{ github.run_number }} | ||
| if-no-files-found: warn | ||
| path: | | ||
| build/xcode-version.txt | ||
| build/logs/** | ||
| fastlane/report.xml | ||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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) | ||||||
|
|
@@ -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 | ||||||
|
|
||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix trailing newline lint warning. SwiftLint reports the file ending does not satisfy the single trailing newline rule. ✂️ Minimal formatting fix-#endif
-
+#endifAs per coding guidelines: 📝 Committable suggestion
Suggested change
🧰 Tools🪛 SwiftLint (0.63.2)[Warning] 325-325: Files should have a single trailing newline (trailing_newline) 🤖 Prompt for AI Agents |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,10 +29,6 @@ private enum MainTabbarTabs: Int, CaseIterable { | |
| } | ||
|
|
||
| extension MainTabbarTabs { | ||
| var isEmpty: Bool { | ||
| self == .payment | ||
| } | ||
|
|
||
| var icon: UIImage { | ||
| let name: String | ||
|
|
||
|
|
@@ -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: | ||
|
|
@@ -51,7 +47,7 @@ extension MainTabbarTabs { | |
|
|
||
| return UIImage(named: name)!.withRenderingMode(.alwaysOriginal) | ||
| } | ||
|
|
||
| var selectedIcon: UIImage { | ||
| let name: String | ||
|
|
||
|
|
@@ -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: | ||
|
|
@@ -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? | ||
|
|
@@ -94,7 +90,7 @@ class MainTabbarController: UITabBarController { | |
| @objc | ||
| weak var wipeDelegate: DWWipeDelegate? | ||
|
|
||
| private var paymentButton: PaymentButton! | ||
| private var paymentIsOpened = false | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if paymentIsOpened is read anywhere in the codebase
rg -n 'paymentIsOpened' --type swift -C2Repository: dashpay/dashwallet-ios Length of output: 1829 Remove the unused This property is assigned in 🤖 Prompt for AI Agents |
||
|
|
||
| @objc | ||
| var isDemoMode = false | ||
|
|
@@ -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? { | ||
|
|
@@ -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 | ||
|
|
@@ -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 { | ||
|
|
@@ -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 | ||
|
|
@@ -378,7 +361,7 @@ extension MainTabbarController: PaymentsViewControllerDelegate { | |
| } | ||
|
|
||
| func paymentsViewControllerWantsToImportPrivateKey(_ controller: PaymentsViewController) { | ||
| paymentButton.isOpened = false | ||
| paymentIsOpened = false | ||
|
|
||
| controller.dismiss(animated: true) { | ||
| self.performScanQRCodeAction() | ||
|
|
@@ -398,7 +381,7 @@ extension MainTabbarController: HomeViewControllerDelegate { | |
| } | ||
|
|
||
| func showPaymentsController(withActivePage pageIndex: PaymentsViewControllerState) { | ||
| paymentButton.isOpened = true | ||
| paymentIsOpened = true | ||
|
|
||
| let receiveModel = DWReceiveModel() | ||
| let payModel = DWPayModel() | ||
|
|
@@ -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 | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
maxim-lobanov/setup-xcode action xcode-version input accepted formats💡 Result:
The xcode-version input for the maxim-lobanov/setup-xcode GitHub Action accepts the following formats: - latest (latest Xcode version including betas available on the runner) - latest-stable (latest stable Xcode version) - SemVer strings, such as: - 16 - 16.4 - 26.3 - ^16.2.0 (SemVer range) - SemVer string followed by -beta (e.g., 16-beta) to select among beta releases Specific versions should be wrapped in single quotes in YAML (e.g., '16.4') to preserve trailing zeros, as GitHub Actions trims them from numbers. Available versions depend on the macOS runner image (e.g., macos-latest, macos-15, macos-26); check the GitHub runner-images repository for the full list pre-installed on each image. Examples: - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '16.4'
Citations:
Replace
xcode-version: "26.x"with a valid format — the "X.x" shorthand is not supported.The
setup-xcodeaction accepts SemVer strings (e.g.,26,26.3) or SemVer ranges (e.g.,^26.0.0), but not the26.xformat. This will likely fail or silently fall back to the runner's default Xcode. Usexcode-version: "26"for any 26.x version, or specify an exact version like"26.3".🤖 Prompt for AI Agents