summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJon Petersson <jon.petersson@mullvad.net>2025-03-05 10:24:31 +0100
committerJon Petersson <jon.petersson@mullvad.net>2025-03-06 10:36:05 +0100
commitd1a60639626773ad495d8a5c90cd51dd473aa7f3 (patch)
tree2beab96e83da6699e6040d01c11a7bf526ffd62a
parent319589b4ec1020b4da217bbc0ae5456ec889b7ab (diff)
downloadmullvadvpn-d1a60639626773ad495d8a5c90cd51dd473aa7f3.tar.xz
mullvadvpn-d1a60639626773ad495d8a5c90cd51dd473aa7f3.zip
Make account number in welcome view copyable
-rw-r--r--ios/MullvadVPN/Classes/AccessbilityIdentifier.swift1
-rw-r--r--ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift64
-rw-r--r--ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeViewController.swift4
3 files changed, 66 insertions, 3 deletions
diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
index ea585cebcf..c94c188e34 100644
--- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
+++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
@@ -32,6 +32,7 @@ public enum AccessibilityIdentifier: Equatable {
case revokedDeviceLoginButton
case dnsSettingsEditButton
case infoButton
+ case copyButton
case learnAboutPrivacyButton
case logOutDeviceConfirmButton
case logOutDeviceCancelButton
diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift
index a892e15baf..5ed49896a0 100644
--- a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift
+++ b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift
@@ -11,6 +11,7 @@ import UIKit
protocol WelcomeContentViewDelegate: AnyObject, Sendable {
func didTapPurchaseButton(welcomeContentView: WelcomeContentView, button: AppButton)
func didTapInfoButton(welcomeContentView: WelcomeContentView, button: UIButton)
+ func didTapCopyButton(welcomeContentView: WelcomeContentView, button: UIButton)
}
struct WelcomeViewModel: Sendable {
@@ -19,6 +20,8 @@ struct WelcomeViewModel: Sendable {
}
final class WelcomeContentView: UIView, Sendable {
+ private var revertCopyImageWorkItem: DispatchWorkItem?
+
private let titleLabel: UILabel = {
let label = UILabel()
label.font = .preferredFont(forTextStyle: .largeTitle, weight: .bold)
@@ -62,6 +65,14 @@ final class WelcomeContentView: UIView, Sendable {
return label
}()
+ private let copyButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setAccessibilityIdentifier(.copyButton)
+ button.tintColor = .white
+ button.setContentHuggingPriority(.defaultHigh, for: .horizontal)
+ return button
+ }()
+
private let deviceNameLabel: UILabel = {
let label = UILabel()
label.adjustsFontForContentSizeCategory = true
@@ -124,6 +135,14 @@ final class WelcomeContentView: UIView, Sendable {
return stackView
}()
+ private let accountRowStackView: UIStackView = {
+ let stackView = UIStackView()
+ stackView.axis = .horizontal
+ stackView.distribution = .fill
+ stackView.spacing = UIMetrics.padding8
+ return stackView
+ }()
+
private let deviceRowStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
@@ -175,12 +194,16 @@ final class WelcomeContentView: UIView, Sendable {
}
private func configureUI() {
+ accountRowStackView.addArrangedSubview(accountNumberLabel)
+ accountRowStackView.addArrangedSubview(copyButton)
+ accountRowStackView.addArrangedSubview(UIView()) // To push content to the left.
+
textsStackView.addArrangedSubview(titleLabel)
textsStackView.setCustomSpacing(UIMetrics.padding8, after: titleLabel)
textsStackView.addArrangedSubview(subtitleLabel)
textsStackView.setCustomSpacing(UIMetrics.padding16, after: subtitleLabel)
- textsStackView.addArrangedSubview(accountNumberLabel)
- textsStackView.setCustomSpacing(UIMetrics.padding16, after: accountNumberLabel)
+ textsStackView.addArrangedSubview(accountRowStackView)
+ textsStackView.setCustomSpacing(UIMetrics.padding16, after: accountRowStackView)
deviceRowStackView.addArrangedSubview(deviceNameLabel)
deviceRowStackView.setCustomSpacing(UIMetrics.padding8, after: deviceNameLabel)
@@ -196,6 +219,8 @@ final class WelcomeContentView: UIView, Sendable {
addSubview(textsStackView)
addSubview(buttonsStackView)
addConstraints()
+
+ showCheckmark(false)
}
private func addConstraints() {
@@ -209,7 +234,7 @@ final class WelcomeContentView: UIView, Sendable {
}
private func addActions() {
- [purchaseButton, infoButton].forEach {
+ [purchaseButton, infoButton, copyButton].forEach {
$0.addTarget(self, action: #selector(tapped(button:)), for: .touchUpInside)
}
}
@@ -220,7 +245,40 @@ final class WelcomeContentView: UIView, Sendable {
delegate?.didTapPurchaseButton(welcomeContentView: self, button: button)
case AccessibilityIdentifier.infoButton.asString:
delegate?.didTapInfoButton(welcomeContentView: self, button: button)
+ case AccessibilityIdentifier.copyButton.asString:
+ didTapCopyAccountNumber()
default: return
}
}
+
+ private func showCheckmark(_ showCheckmark: Bool) {
+ if showCheckmark {
+ let tickIcon = UIImage(named: "IconTick")
+
+ copyButton.setImage(tickIcon, for: .normal)
+ copyButton.tintColor = .successColor
+ } else {
+ let copyIcon = UIImage(named: "IconCopy")
+
+ copyButton.setImage(copyIcon, for: .normal)
+ copyButton.tintColor = .white
+ }
+ }
+
+ @objc private func didTapCopyAccountNumber() {
+ let delayedWorkItem = DispatchWorkItem { [weak self] in
+ self?.showCheckmark(false)
+ }
+
+ revertCopyImageWorkItem?.cancel()
+ revertCopyImageWorkItem = delayedWorkItem
+
+ showCheckmark(true)
+ delegate?.didTapCopyButton(welcomeContentView: self, button: copyButton)
+
+ DispatchQueue.main.asyncAfter(
+ deadline: .now() + .seconds(2),
+ execute: delayedWorkItem
+ )
+ }
}
diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeViewController.swift b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeViewController.swift
index e112d7cb29..a1deac16c0 100644
--- a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeViewController.swift
+++ b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeViewController.swift
@@ -83,4 +83,8 @@ extension WelcomeViewController: @preconcurrency WelcomeContentViewDelegate {
func didTapPurchaseButton(welcomeContentView: WelcomeContentView, button: AppButton) {
delegate?.didRequestToViewPurchaseOptions(accountNumber: interactor.accountNumber)
}
+
+ func didTapCopyButton(welcomeContentView: WelcomeContentView, button: UIButton) {
+ UIPasteboard.general.string = interactor.accountNumber
+ }
}