diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2025-06-09 16:08:24 +0200 |
|---|---|---|
| committer | Jon Petersson <jon.petersson@mullvad.net> | 2025-06-23 11:53:36 +0200 |
| commit | 90cd5b179b19c27215dbbcc85993c9957ba10411 (patch) | |
| tree | 4f2f2e3cc7fbd34900aa0d5ecdb158503bfe1d82 | |
| parent | 75d3d8c4c5283da940d0194f89d6b3ab9b38e151 (diff) | |
| download | mullvadvpn-90cd5b179b19c27215dbbcc85993c9957ba10411.tar.xz mullvadvpn-90cd5b179b19c27215dbbcc85993c9957ba10411.zip | |
Enable more use of dynamic fonts
43 files changed, 611 insertions, 79 deletions
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md index 1b681ad1ac..23cf7a809a 100644 --- a/ios/CHANGELOG.md +++ b/ios/CHANGELOG.md @@ -26,6 +26,7 @@ Line wrap the file at 100 chars. Th - Make feature indicators clickable shortcuts to their corresponding settings. - Let users cancel sending a problem report. - Add possibility to manage devices from account view. +- Add support for Dynamic Type to allow fonts to scale according to user's system settings. ### Changed - Replace Classic McEliece with HQC as one of the post-quantum safe key exchange diff --git a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift index 977296c532..9188a9cd50 100644 --- a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift +++ b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift @@ -31,6 +31,7 @@ class HeaderBarView: UIView { private lazy var deviceNameLabel: UILabel = { let label = UILabel() label.font = .mullvadMiniSemiBold + label.adjustsFontForContentSizeCategory = true label.textColor = UIColor(white: 1.0, alpha: 0.8) label.setContentHuggingPriority(.defaultHigh, for: .horizontal) label.setAccessibilityIdentifier(.headerDeviceNameLabel) @@ -40,6 +41,7 @@ class HeaderBarView: UIView { private lazy var timeLeftLabel: UILabel = { let label = UILabel() label.font = .mullvadMiniSemiBold + label.adjustsFontForContentSizeCategory = true label.textColor = UIColor(white: 1.0, alpha: 0.8) label.setContentHuggingPriority(.defaultLow, for: .horizontal) return label diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/AboutViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/AboutViewController.swift index 0752fee599..27c790bd89 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/AboutViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/AboutViewController.swift @@ -56,7 +56,8 @@ class AboutViewController: UIViewController { let label = UILabel() label.text = header - label.font = .systemFont(ofSize: 28, weight: .bold) + label.font = .mullvadLarge + label.adjustsFontForContentSizeCategory = true label.textColor = .primaryTextColor label.numberOfLines = 0 label.textAlignment = .center @@ -69,7 +70,8 @@ class AboutViewController: UIViewController { let label = UILabel() label.text = preamble - label.font = .systemFont(ofSize: 18) + label.font = .mullvadSmall + label.adjustsFontForContentSizeCategory = true label.textColor = .primaryTextColor label.numberOfLines = 0 label.textAlignment = .center @@ -82,7 +84,8 @@ class AboutViewController: UIViewController { let label = UILabel() label.text = text - label.font = .systemFont(ofSize: 15) + label.font = .mullvadTiny + label.adjustsFontForContentSizeCategory = true label.textColor = .secondaryTextColor label.numberOfLines = 0 diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentConfiguration.swift index fbae59d0fe..c1d9621f38 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentConfiguration.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentConfiguration.swift @@ -11,17 +11,20 @@ import UIKit /// Content configuration presenting a label and switch control. struct ListCellContentConfiguration: UIContentConfiguration, Equatable { struct TextProperties: Equatable { - var font = UIFont.systemFont(ofSize: 17) + var font = UIFont.mullvadSmall + var adjustsFontForContentSizeCategory = true var color = UIColor.Cell.titleTextColor } struct SecondaryTextProperties: Equatable { - var font = UIFont.systemFont(ofSize: 17) + var font = UIFont.mullvadSmall + var adjustsFontForContentSizeCategory = true var color = UIColor.Cell.detailTextColor.withAlphaComponent(0.8) } struct TertiaryTextProperties: Equatable { - var font = UIFont.systemFont(ofSize: 15) + var font = UIFont.mullvadTiny + var adjustsFontForContentSizeCategory = true var color = UIColor.Cell.titleTextColor.withAlphaComponent(0.6) } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentView.swift index 57264e88d5..6f40b6b8ad 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/ListCellContentView.swift @@ -59,6 +59,7 @@ class ListCellContentView: UIView, UIContentView, UITextFieldDelegate { let textProperties = actualConfiguration.textProperties textLabel.font = textProperties.font + textLabel.adjustsFontForContentSizeCategory = textProperties.adjustsFontForContentSizeCategory textLabel.textColor = textProperties.color textLabel.text = actualConfiguration.text @@ -68,6 +69,7 @@ class ListCellContentView: UIView, UIContentView, UITextFieldDelegate { let textProperties = actualConfiguration.secondaryTextProperties secondaryTextLabel.font = textProperties.font + secondaryTextLabel.adjustsFontForContentSizeCategory = textProperties.adjustsFontForContentSizeCategory secondaryTextLabel.textColor = textProperties.color secondaryTextLabel.text = actualConfiguration.secondaryText @@ -77,6 +79,7 @@ class ListCellContentView: UIView, UIContentView, UITextFieldDelegate { let textProperties = actualConfiguration.tertiaryTextProperties tertiaryTextLabel.font = textProperties.font + tertiaryTextLabel.adjustsFontForContentSizeCategory = textProperties.adjustsFontForContentSizeCategory tertiaryTextLabel.textColor = textProperties.color tertiaryTextLabel.text = actualConfiguration.tertiaryText diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift index 8a68a72164..3a98733ca2 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift @@ -11,7 +11,7 @@ import UIKit /// Content configuration presenting a label and switch control. struct SwitchCellContentConfiguration: UIContentConfiguration, Equatable { struct TextProperties: Equatable { - var font = UIFont.systemFont(ofSize: 17) + var font = UIFont.mullvadSmall var color = UIColor.Cell.titleTextColor } diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift index cbf50170aa..a4e2239768 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift @@ -68,6 +68,7 @@ class SwitchCellContentView: UIView, UIContentView, UITextFieldDelegate { let textProperties = actualConfiguration.textProperties textLabel.font = textProperties.font + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = textProperties.color textLabel.text = actualConfiguration.text diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration.swift index 97d7bba9d0..f011975517 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentConfiguration.swift @@ -49,7 +49,8 @@ struct TextCellContentConfiguration: UIContentConfiguration, Equatable { extension TextCellContentConfiguration { /// The text label properties. struct TextProperties: Equatable { - var font = UIFont.systemFont(ofSize: 17) + var font = UIFont.mullvadSmall + var adjustsFontForContentSizeCategory = true var color = UIColor.Cell.titleTextColor } @@ -77,7 +78,10 @@ extension TextCellContentConfiguration { /// Text field configuration. struct TextFieldProperties: Equatable { /// Text font. - var font = UIFont.systemFont(ofSize: 17) + var font = UIFont.mullvadSmall + + var adjustsFontForContentSizeCategory = true + /// Text color. var textColor = UIColor.Cell.textFieldTextColor diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentView.swift index 46f52ac996..43ac40bbd3 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/TextCellContentView.swift @@ -71,6 +71,7 @@ class TextCellContentView: UIView, UIContentView, UIGestureRecognizerDelegate, S textLabel.font = textProperties.font textLabel.textColor = textProperties.color + textLabel.adjustsFontForContentSizeCategory = true textLabel.text = actualConfiguration.text } @@ -178,6 +179,7 @@ extension TextCellContentConfiguration.TextFieldProperties { @MainActor func apply(to textField: CustomTextField) { textField.font = font + textField.adjustsFontForContentSizeCategory = adjustsFontForContentSizeCategory textField.backgroundColor = .clear textField.textColor = textColor textField.placeholderTextColor = placeholderColor diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift index 1f1742c1bd..97afabdce1 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift @@ -74,7 +74,8 @@ class EditAccessMethodViewController: UIViewController { private func createTitle() -> UIView { let label = UILabel() - label.font = UIFont.preferredFont(forTextStyle: .largeTitle, weight: .bold) + label.font = .mullvadBig + label.adjustsFontForContentSizeCategory = true label.numberOfLines = 0 label.lineBreakMode = .byWordWrapping label.lineBreakStrategy = [] diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift index 9b5a09d4cd..ce3efe478b 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift @@ -267,7 +267,7 @@ class MethodSettingsViewController: UITableViewController { let validationResult = Result { try subject.value.validate() } let validationError = validationResult.error as? AccessMethodValidationError - // Only look for format errors for test(save validation. + // Only look for format errors for test (save validation). contentValidationErrors = validationError?.fieldErrors.filter { error in error.kind != .emptyValue } ?? [] diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatusView.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatusView.swift index fbb1ef2102..1618f9079f 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatusView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideStatusView.swift @@ -11,7 +11,8 @@ import UIKit class IPOverrideStatusView: UIView { private lazy var titleLabel: UILabel = { let label = UILabel() - label.font = .systemFont(ofSize: 15, weight: .bold) + label.font = .mullvadTinySemiBold + label.adjustsFontForContentSizeCategory = true label.textColor = .white return label }() @@ -22,7 +23,8 @@ class IPOverrideStatusView: UIView { private lazy var descriptionLabel: UILabel = { let label = UILabel() - label.font = .systemFont(ofSize: 12, weight: .semibold) + label.font = .mullvadMiniSemiBold + label.adjustsFontForContentSizeCategory = true label.textColor = .white.withAlphaComponent(0.6) label.numberOfLines = 0 return label diff --git a/ios/MullvadVPN/Coordinators/Settings/Views/SwitchRowView.swift b/ios/MullvadVPN/Coordinators/Settings/Views/SwitchRowView.swift index 392be7934f..e4540c0ccc 100644 --- a/ios/MullvadVPN/Coordinators/Settings/Views/SwitchRowView.swift +++ b/ios/MullvadVPN/Coordinators/Settings/Views/SwitchRowView.swift @@ -27,7 +27,7 @@ struct SwitchRowView: View { infoButtonAction: didTapInfoButton )) .disabled(disabled) - .font(.headline) + .font(.mullvadSmall) .frame(height: UIMetrics.SettingsRowView.height) .padding(UIMetrics.SettingsRowView.layoutMargins) .background(Color(.primaryColor)) diff --git a/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift b/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift index a68406908f..2247f826c2 100644 --- a/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift +++ b/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift @@ -12,8 +12,11 @@ extension UIListContentConfiguration { /// Returns cell configured with default text attribute used in Mullvad UI. static func mullvadCell(tableStyle: UITableView.Style, isEnabled: Bool = true) -> UIListContentConfiguration { var configuration = cell() - configuration.textProperties.font = .systemFont(ofSize: 17) + configuration.textProperties.font = .mullvadSmall + configuration.textProperties.adjustsFontForContentSizeCategory = true configuration.textProperties.color = .Cell.titleTextColor.withAlphaComponent(isEnabled ? 1 : 0.8) + configuration.secondaryTextProperties.font = .mullvadSmall + configuration.secondaryTextProperties.adjustsFontForContentSizeCategory = true applyMargins(to: &configuration, tableStyle: tableStyle) @@ -23,10 +26,12 @@ extension UIListContentConfiguration { /// Returns value cell configured with default text attribute used in Mullvad UI. static func mullvadValueCell(tableStyle: UITableView.Style, isEnabled: Bool = true) -> UIListContentConfiguration { var configuration = valueCell() - configuration.textProperties.font = .systemFont(ofSize: 17) + configuration.textProperties.font = .mullvadSmall + configuration.textProperties.adjustsFontForContentSizeCategory = true configuration.textProperties.color = .Cell.titleTextColor.withAlphaComponent(isEnabled ? 1 : 0.8) configuration.secondaryTextProperties.color = .Cell.detailTextColor.withAlphaComponent(0.8) - configuration.secondaryTextProperties.font = .systemFont(ofSize: 17) + configuration.secondaryTextProperties.font = .mullvadSmall + configuration.secondaryTextProperties.adjustsFontForContentSizeCategory = true applyMargins(to: &configuration, tableStyle: tableStyle) @@ -37,7 +42,8 @@ extension UIListContentConfiguration { static func mullvadGroupedHeader(tableStyle: UITableView.Style) -> UIListContentConfiguration { var configuration = groupedHeader() configuration.textProperties.color = .TableSection.headerTextColor - configuration.textProperties.font = .systemFont(ofSize: 13) + configuration.textProperties.font = .mullvadTiny + configuration.textProperties.adjustsFontForContentSizeCategory = true applyMargins(to: &configuration, tableStyle: tableStyle) @@ -48,7 +54,8 @@ extension UIListContentConfiguration { static func mullvadGroupedFooter(tableStyle: UITableView.Style) -> UIListContentConfiguration { var configuration = groupedFooter() configuration.textProperties.color = .TableSection.footerTextColor - configuration.textProperties.font = .systemFont(ofSize: 13) + configuration.textProperties.font = .mullvadMini + configuration.textProperties.adjustsFontForContentSizeCategory = true applyMargins(to: &configuration, tableStyle: tableStyle) diff --git a/ios/MullvadVPN/Notifications/UI/NotificationBannerView.swift b/ios/MullvadVPN/Notifications/UI/NotificationBannerView.swift index 54b2695b3e..ff7f5f016b 100644 --- a/ios/MullvadVPN/Notifications/UI/NotificationBannerView.swift +++ b/ios/MullvadVPN/Notifications/UI/NotificationBannerView.swift @@ -14,6 +14,7 @@ final class NotificationBannerView: UIView { private let titleLabel: UILabel = { let textLabel = UILabel() textLabel.font = .mullvadTinySemiBold + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = UIColor.InAppNotificationBanner.titleColor textLabel.numberOfLines = 0 textLabel.lineBreakMode = .byWordWrapping @@ -24,6 +25,7 @@ final class NotificationBannerView: UIView { private let bodyLabel: UILabel = { let textLabel = UILabel() textLabel.font = .mullvadTiny + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = UIColor.InAppNotificationBanner.bodyColor textLabel.numberOfLines = 0 textLabel.lineBreakMode = .byWordWrapping diff --git a/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift b/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift index 54b9188a1d..399358c82a 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountDeviceRow.swift @@ -27,14 +27,16 @@ class AccountDeviceRow: UIView { value: "Device name", comment: "" ) - label.font = UIFont.systemFont(ofSize: 14) + label.font = .mullvadTiny + label.adjustsFontForContentSizeCategory = true label.textColor = UIColor(white: 1.0, alpha: 0.6) return label }() private let deviceLabel: UILabel = { let label = UILabel() - label.font = UIFont.systemFont(ofSize: 17) + label.font = .mullvadSmall + label.adjustsFontForContentSizeCategory = true label.textColor = .white return label }() @@ -42,6 +44,7 @@ class AccountDeviceRow: UIView { private let deviceManagementButton: UIButton = { let button = IncreasedHitButton(type: .system) button.isExclusiveTouch = true + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.setAccessibilityIdentifier(.deviceManagementButton) let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.mullvadSmallSemiBold, diff --git a/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift b/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift index 4f39673bea..00ebb6b16e 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountExpiryRow.swift @@ -52,7 +52,8 @@ class AccountExpiryRow: UIView { value: "Paid until", comment: "" ) - textLabel.font = UIFont.systemFont(ofSize: 14) + textLabel.font = .mullvadTiny + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = UIColor(white: 1.0, alpha: 0.6) return textLabel }() @@ -60,7 +61,8 @@ class AccountExpiryRow: UIView { private let valueLabel: UILabel = { let valueLabel = UILabel() valueLabel.translatesAutoresizingMaskIntoConstraints = false - valueLabel.font = UIFont.systemFont(ofSize: 17) + valueLabel.font = .mullvadSmall + valueLabel.adjustsFontForContentSizeCategory = true valueLabel.textColor = .white valueLabel.setAccessibilityIdentifier(.accountPagePaidUntilLabel) return valueLabel diff --git a/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift b/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift index c14197f32b..6dbc787f58 100644 --- a/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift +++ b/ios/MullvadVPN/View controllers/Account/AccountNumberRow.swift @@ -32,14 +32,16 @@ class AccountNumberRow: UIView { value: "Account number", comment: "" ) - textLabel.font = UIFont.systemFont(ofSize: 14) + textLabel.font = .mullvadTiny + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = UIColor(white: 1.0, alpha: 0.6) return textLabel }() private let accountNumberLabel: UILabel = { let textLabel = UILabel() - textLabel.font = UIFont.monospacedSystemFont(ofSize: 17, weight: .regular) + textLabel.font = .mullvadMiniSemiBold + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = .white return textLabel }() @@ -47,12 +49,14 @@ class AccountNumberRow: UIView { private let showHideButton: UIButton = { let button = UIButton(type: .system) button.tintColor = .white + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.setContentHuggingPriority(.defaultHigh, for: .horizontal) return button }() private let copyButton: UIButton = { let button = UIButton(type: .system) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.tintColor = .white button.setContentHuggingPriority(.defaultHigh, for: .horizontal) return button diff --git a/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift b/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift index 3de7d1376a..87c85913bb 100644 --- a/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift +++ b/ios/MullvadVPN/View controllers/Account/RestorePurchasesView.swift @@ -26,6 +26,7 @@ class RestorePurchasesView: UIView { let label = UILabel() label.setAccessibilityIdentifier(.restorePurchasesButton) label.attributedText = makeAttributedString() + label.adjustsFontForContentSizeCategory = true label.isUserInteractionEnabled = true label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapRestoreButton))) return label @@ -69,7 +70,7 @@ class RestorePurchasesView: UIView { ) return NSAttributedString(string: text, attributes: [ - .font: UIFont.systemFont(ofSize: 13, weight: .semibold), + .font: UIFont.mullvadMini, .foregroundColor: UIColor.white, .underlineStyle: NSUnderlineStyle.single.rawValue, ]) diff --git a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift index 521b5bc95f..6772016fba 100644 --- a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift +++ b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift @@ -34,8 +34,9 @@ class AccountDeletionContentView: UIView { private let titleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = .preferredFont(forTextStyle: .title2, weight: .bold) + label.font = .mullvadLarge label.numberOfLines = .zero + label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .white label.text = NSLocalizedString( @@ -50,8 +51,9 @@ class AccountDeletionContentView: UIView { private let messageLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = .preferredFont(forTextStyle: .body, weight: .bold) + label.font = .mullvadSmallSemiBold label.numberOfLines = .zero + label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .white return label @@ -60,8 +62,9 @@ class AccountDeletionContentView: UIView { private let tipLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = .preferredFont(forTextStyle: .footnote, weight: .bold) + label.font = .mullvadMiniSemiBold label.numberOfLines = .zero + label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .white label.text = NSLocalizedString( @@ -82,7 +85,7 @@ class AccountDeletionContentView: UIView { let groupingStyle = AccountTextField.GroupingStyle.lastPart let textField = AccountTextField(groupingStyle: groupingStyle) textField.setAccessibilityIdentifier(.deleteAccountTextField) - textField.font = .preferredFont(forTextStyle: .body, weight: .bold) + textField.font = .mullvadSmallSemiBold textField.placeholder = Array(repeating: "X", count: 4).joined() textField.placeholderTextColor = .lightGray textField.textContentType = .username @@ -94,6 +97,7 @@ class AccountDeletionContentView: UIView { textField.keyboardType = .numberPad textField.returnKeyType = .done textField.enablesReturnKeyAutomatically = false + textField.adjustsFontForContentSizeCategory = true textField.backgroundColor = .white textField.borderStyle = .line return textField @@ -161,6 +165,7 @@ class AccountDeletionContentView: UIView { let label = UILabel() label.font = .preferredFont(forTextStyle: .body) label.numberOfLines = 2 + label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .red label.setContentHuggingPriority(.defaultLow, for: .horizontal) diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift index ec5db174a9..3bc8e317bc 100644 --- a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift +++ b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift @@ -24,7 +24,7 @@ final class WelcomeContentView: UIView, Sendable { private let titleLabel: UILabel = { let label = UILabel() - label.font = .preferredFont(forTextStyle: .largeTitle, weight: .bold) + label.font = .mullvadLarge label.textColor = .white label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping @@ -40,7 +40,7 @@ final class WelcomeContentView: UIView, Sendable { private let subtitleLabel: UILabel = { let label = UILabel() - label.font = .preferredFont(forTextStyle: .body) + label.font = .mullvadSmall label.textColor = .white label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping @@ -60,7 +60,7 @@ final class WelcomeContentView: UIView, Sendable { label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.numberOfLines = .zero - label.font = .preferredFont(forTextStyle: .title2, weight: .bold) + label.font = .mullvadMedium label.textColor = .white return label }() @@ -68,6 +68,7 @@ final class WelcomeContentView: UIView, Sendable { private let copyButton: UIButton = { let button = UIButton(type: .system) button.setAccessibilityIdentifier(.copyButton) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.tintColor = .white button.setContentHuggingPriority(.defaultHigh, for: .horizontal) return button @@ -77,7 +78,7 @@ final class WelcomeContentView: UIView, Sendable { let label = UILabel() label.adjustsFontForContentSizeCategory = true label.translatesAutoresizingMaskIntoConstraints = false - label.font = .preferredFont(forTextStyle: .body) + label.font = .mullvadSmall label.textColor = .white label.setContentHuggingPriority(.defaultLow, for: .horizontal) label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) @@ -87,6 +88,7 @@ final class WelcomeContentView: UIView, Sendable { private let infoButton: UIButton = { let button = IncreasedHitButton(type: .system) button.setAccessibilityIdentifier(.infoButton) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.tintColor = .white button.translatesAutoresizingMaskIntoConstraints = false button.setImage(UIImage.Buttons.info, for: .normal) @@ -97,7 +99,7 @@ final class WelcomeContentView: UIView, Sendable { private let descriptionLabel: UILabel = { let label = UILabel() - label.font = .preferredFont(forTextStyle: .body) + label.font = .mullvadSmall label.adjustsFontForContentSizeCategory = true label.textColor = .white label.numberOfLines = .zero diff --git a/ios/MullvadVPN/View controllers/DeviceList/DeviceManagementContentView.swift b/ios/MullvadVPN/View controllers/DeviceList/DeviceManagementContentView.swift new file mode 100644 index 0000000000..7e98cd8f9e --- /dev/null +++ b/ios/MullvadVPN/View controllers/DeviceList/DeviceManagementContentView.swift @@ -0,0 +1,321 @@ +// +// DeviceManagementContentView.swift +// MullvadVPN +// +// Created by pronebird on 19/07/2022. +// Copyright © 2025 Mullvad VPN AB. All rights reserved. +// + +import UIKit + +class DeviceManagementContentView: UIView { + private let scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + return scrollView + }() + + let scrollContentView: UIView = { + let view = UIView() + view.directionalLayoutMargins = UIMetrics.contentLayoutMargins + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + let statusImageView: StatusImageView = { + let imageView = StatusImageView(style: .failure) + imageView.translatesAutoresizingMaskIntoConstraints = false + return imageView + }() + + let titleLabel: UILabel = { + let textLabel = UILabel() + textLabel.font = .mullvadLarge + textLabel.adjustsFontForContentSizeCategory = true + textLabel.textColor = .white + textLabel.translatesAutoresizingMaskIntoConstraints = false + return textLabel + }() + + let messageLabel: UILabel = { + let textLabel = UILabel() + textLabel.font = .mullvadSmall + textLabel.adjustsFontForContentSizeCategory = true + textLabel.textColor = .white + textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.numberOfLines = 0 + textLabel.lineBreakStrategy = [] + return textLabel + }() + + let deviceStackView: UIStackView = { + let stackView = UIStackView(arrangedSubviews: []) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.spacing = 1 + stackView.clipsToBounds = true + stackView.distribution = .fillEqually + return stackView + }() + + let continueButton: AppButton = { + let button = AppButton(style: .success) + button.translatesAutoresizingMaskIntoConstraints = false + button.setTitle( + NSLocalizedString( + "CONTINUE_BUTTON", + tableName: "DeviceManagement", + value: "Continue with login", + comment: "" + ), + for: .normal + ) + button.isEnabled = false + button.setAccessibilityIdentifier(.continueWithLoginButton) + return button + }() + + let cancelButton: AppButton = { + let button = AppButton(style: .default) + button.translatesAutoresizingMaskIntoConstraints = false + button.setTitle( + NSLocalizedString( + "CANCEL_BUTTON", + tableName: "DeviceManagement", + value: "Cancel", + comment: "" + ), + for: .normal + ) + return button + }() + + private lazy var buttonStackView: UIStackView = { + let stackView = UIStackView(arrangedSubviews: [continueButton, cancelButton]) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.spacing = UIMetrics.interButtonSpacing + return stackView + }() + + var handleDeviceDeletion: (@Sendable (DeviceViewModel, @escaping @Sendable () -> Void) -> Void)? + + private var currentDeviceModels = [DeviceViewModel]() + + var canContinue = false { + didSet { + updateView() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + addViews() + constraintViews() + updateView() + + setAccessibilityIdentifier(.deviceManagementView) + } + + private func addViews() { + try? [scrollView, buttonStackView].forEach(addSubview) + + scrollView.addSubview(scrollContentView) + + try? [statusImageView, titleLabel, messageLabel, deviceStackView] + .forEach(scrollContentView.addSubview) + } + + private func constraintViews() { + NSLayoutConstraint.activate([ + scrollView.topAnchor.constraint(equalTo: topAnchor, constant: 16), + scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), + + buttonStackView.topAnchor.constraint( + equalTo: scrollView.bottomAnchor, + constant: UIMetrics.contentLayoutMargins.top + ), + buttonStackView.leadingAnchor.constraint( + equalTo: leadingAnchor, + constant: UIMetrics.contentLayoutMargins.leading + ), + buttonStackView.trailingAnchor.constraint( + equalTo: trailingAnchor, + constant: -UIMetrics.contentLayoutMargins.trailing + ), + buttonStackView.bottomAnchor.constraint( + equalTo: safeAreaLayoutGuide.bottomAnchor, + constant: -UIMetrics.contentLayoutMargins.bottom + ), + + scrollContentView.topAnchor.constraint(equalTo: scrollView.topAnchor), + scrollContentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), + scrollContentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), + scrollContentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), + scrollContentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), + + statusImageView.topAnchor + .constraint(equalTo: scrollContentView.topAnchor), + statusImageView.centerXAnchor.constraint(equalTo: scrollContentView.centerXAnchor), + + titleLabel.topAnchor.constraint(equalTo: statusImageView.bottomAnchor, constant: 22), + titleLabel.leadingAnchor + .constraint(equalTo: scrollContentView.layoutMarginsGuide.leadingAnchor), + titleLabel.trailingAnchor + .constraint(equalTo: scrollContentView.layoutMarginsGuide.trailingAnchor), + + messageLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), + messageLabel.leadingAnchor + .constraint(equalTo: scrollContentView.layoutMarginsGuide.leadingAnchor), + messageLabel.trailingAnchor + .constraint(equalTo: scrollContentView.layoutMarginsGuide.trailingAnchor), + + deviceStackView.topAnchor.constraint( + equalTo: messageLabel.bottomAnchor, + constant: UIMetrics.TableView.sectionSpacing + ), + deviceStackView.leadingAnchor.constraint(equalTo: scrollContentView.leadingAnchor), + deviceStackView.trailingAnchor.constraint(equalTo: scrollContentView.trailingAnchor), + deviceStackView.bottomAnchor.constraint(equalTo: scrollContentView.bottomAnchor), + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setDeviceViewModels(_ newModels: [DeviceViewModel], animated: Bool) { + let difference = newModels.difference(from: currentDeviceModels) { newModel, model in + newModel.id == model.id + } + + currentDeviceModels = newModels + + var viewsToAdd: [(view: UIView, offset: Int)] = [] + var viewsToRemove: [UIView] = [] + + difference.forEach { change in + switch change { + case let .insert(offset, model, _): + viewsToAdd.append((createDeviceRowView(from: model), offset)) + case let .remove(offset, _, _): + viewsToRemove.append(deviceStackView.arrangedSubviews[offset]) + } + } + + viewsToAdd.forEach { item in + deviceStackView.insertArrangedSubview(item.view, at: item.offset) + } + + // Layout inserted subviews before running animations to achieve a folding effect. + if animated { + UIView.performWithoutAnimation { + deviceStackView.layoutIfNeeded() + } + } + + if animated { + UIView.animate( + withDuration: 0.25, + delay: 0, + options: [.curveEaseInOut], + animations: { [weak self] in + self?.showHideViews(viewsToAdd: viewsToAdd, viewsToRemove: viewsToRemove) + self?.deviceStackView.layoutIfNeeded() + }, + completion: { [weak self] _ in + self?.removeViews(viewsToRemove: viewsToRemove) + } + ) + } else { + showHideViews(viewsToAdd: viewsToAdd, viewsToRemove: viewsToRemove) + removeViews(viewsToRemove: viewsToRemove) + } + } + + private func showHideViews(viewsToAdd: [(view: UIView, offset: Int)], viewsToRemove: [UIView]) { + viewsToRemove.forEach { view in + view.alpha = 0 + view.isHidden = true + } + + viewsToAdd.forEach { item in + item.view.alpha = 1 + item.view.isHidden = false + } + } + + private func removeViews(viewsToRemove: [UIView]) { + viewsToRemove.forEach { view in + view.removeFromSuperview() + } + } + + private func createDeviceRowView(from model: DeviceViewModel) -> DeviceRowView { + let view = DeviceRowView(viewModel: model) + + view.isHidden = true + view.alpha = 0 + + view.deleteHandler = { [weak self] _ in + view.showsActivityIndicator = true + + self?.handleDeviceDeletion?(view.viewModel) { + Task { @MainActor in + view.showsActivityIndicator = false + } + } + } + + return view + } + + private func updateView() { + titleLabel.text = titleText + messageLabel.text = messageText + continueButton.isEnabled = canContinue + statusImageView.style = canContinue ? .success : .failure + } + + private var titleText: String { + if canContinue { + return NSLocalizedString( + "CONTINUE_LOGIN_TITLE", + tableName: "DeviceManagement", + value: "Super!", + comment: "" + ) + } else { + return NSLocalizedString( + "LOGOUT_DEVICES_TITLE", + tableName: "DeviceManagement", + value: "Too many devices", + comment: "" + ) + } + } + + private var messageText: String { + if canContinue { + return NSLocalizedString( + "CONTINUE_LOGIN_MESSAGE", + tableName: "DeviceManagement", + value: "You can now continue logging in on this device.", + comment: "" + ) + } else { + return NSLocalizedString( + "LOGOUT_DEVICES_MESSAGE", + tableName: "DeviceManagement", + value: """ + Please log out of at least one by removing it from the list below. You can find \ + the corresponding device name under the device’s Account settings. + """, + comment: "" + ) + } + } +} diff --git a/ios/MullvadVPN/View controllers/DeviceList/DeviceRowView.swift b/ios/MullvadVPN/View controllers/DeviceList/DeviceRowView.swift new file mode 100644 index 0000000000..0e3fcea273 --- /dev/null +++ b/ios/MullvadVPN/View controllers/DeviceList/DeviceRowView.swift @@ -0,0 +1,137 @@ +// +// DeviceRowView.swift +// MullvadVPN +// +// Created by pronebird on 26/07/2022. +// Copyright © 2025 Mullvad VPN AB. All rights reserved. +// + +import UIKit + +class DeviceRowView: UIView { + let viewModel: DeviceViewModel + var deleteHandler: ((DeviceRowView) -> Void)? + + let textLabel: UILabel = { + let textLabel = UILabel() + textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.font = .mullvadSmallSemiBold + textLabel.adjustsFontForContentSizeCategory = true + textLabel.textColor = .white + return textLabel + }() + + let activityIndicator: SpinnerActivityIndicatorView = { + let activityIndicator = SpinnerActivityIndicatorView(style: .custom) + activityIndicator.translatesAutoresizingMaskIntoConstraints = false + return activityIndicator + }() + + let creationDateLabel: UILabel = { + let creationDateLabel = UILabel() + creationDateLabel.translatesAutoresizingMaskIntoConstraints = false + creationDateLabel.font = .mullvadMiniSemiBold + creationDateLabel.adjustsFontForContentSizeCategory = true + creationDateLabel.textColor = .white.withAlphaComponent(0.6) + return creationDateLabel + }() + + let removeButton: UIButton = { + let image = UIImage.Buttons.close + .withTintColor( + .white.withAlphaComponent(0.4), + renderingMode: .alwaysOriginal + ) + + let button = IncreasedHitButton(type: .custom) + button.translatesAutoresizingMaskIntoConstraints = false + button.setImage(image, for: .normal) + button.accessibilityLabel = NSLocalizedString( + "REMOVE_DEVICE_ACCESSIBILITY_LABEL", + tableName: "DeviceManagement", + value: "Remove device", + comment: "" + ) + return button + }() + + var showsActivityIndicator = false { + didSet { + removeButton.isHidden = showsActivityIndicator + + if showsActivityIndicator { + activityIndicator.startAnimating() + } else { + activityIndicator.stopAnimating() + } + } + } + + init(viewModel: DeviceViewModel) { + self.viewModel = viewModel + + super.init(frame: .zero) + + setAccessibilityIdentifier(.deviceCell) + backgroundColor = .primaryColor + directionalLayoutMargins = UIMetrics.TableView.rowViewLayoutMargins + + for subview in [textLabel, removeButton, activityIndicator, creationDateLabel] { + addSubview(subview) + } + + textLabel.text = viewModel.name + creationDateLabel.text = .init( + format: + NSLocalizedString( + "CREATED_DEVICE_LABEL", + tableName: "DeviceManagement", + value: "Created: %@", + comment: "" + ), + viewModel.creationDate + ) + + removeButton.addTarget(self, action: #selector(handleButtonTap(_:)), for: .touchUpInside) + removeButton.setAccessibilityIdentifier(.deviceCellRemoveButton) + + NSLayoutConstraint.activate([ + textLabel.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor), + textLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + + creationDateLabel.leadingAnchor.constraint(equalTo: textLabel.leadingAnchor), + creationDateLabel.topAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 4.0), + creationDateLabel.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) + .withPriority(.defaultLow), + creationDateLabel.trailingAnchor.constraint(equalTo: textLabel.trailingAnchor), + + removeButton.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor), + removeButton.leadingAnchor.constraint( + greaterThanOrEqualTo: textLabel.trailingAnchor, + constant: 8 + ), + removeButton.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), + + activityIndicator.centerXAnchor.constraint(equalTo: removeButton.centerXAnchor), + activityIndicator.centerYAnchor.constraint(equalTo: removeButton.centerYAnchor), + + // Bump dimensions by 6pt to account for transparent pixels around spinner image. + activityIndicator.widthAnchor.constraint( + equalTo: removeButton.widthAnchor, + constant: 6 + ), + activityIndicator.heightAnchor.constraint( + equalTo: removeButton.heightAnchor, + constant: 6 + ), + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc private func handleButtonTap(_ sender: Any?) { + deleteHandler?(self) + } +} diff --git a/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift b/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift index d3a2cc142d..13c6a8d684 100644 --- a/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift +++ b/ios/MullvadVPN/View controllers/Login/AccountInputGroupView.swift @@ -51,8 +51,9 @@ final class AccountInputGroupView: UIView { private let privateTextField: AccountTextField = { let textField = AccountTextField() - textField.font = accountNumberFont() + textField.font = .mullvadMedium textField.translatesAutoresizingMaskIntoConstraints = false + textField.adjustsFontForContentSizeCategory = true textField.placeholder = "0000 0000 0000 0000" textField.placeholderTextColor = .lightGray textField.textContentType = .username @@ -107,7 +108,7 @@ final class AccountInputGroupView: UIView { button.configuration? .titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributeContainer in var updatedAttributeContainer = attributeContainer - updatedAttributeContainer.font = AccountInputGroupView.accountNumberFont() + updatedAttributeContainer.font = .mullvadMedium updatedAttributeContainer.foregroundColor = .AccountTextField.NormalState.textColor return updatedAttributeContainer } @@ -375,10 +376,6 @@ final class AccountInputGroupView: UIView { // MARK: - Private - private static func accountNumberFont() -> UIFont { - UIFont.monospacedSystemFont(ofSize: 20, weight: .regular) - } - private func addTextFieldNotificationObservers() { let notificationCenter = NotificationCenter.default diff --git a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift index 542571fe69..23e02d6a41 100644 --- a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift +++ b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift @@ -13,17 +13,19 @@ class LoginContentView: UIView { let titleLabel: UILabel = { let textLabel = UILabel() - textLabel.font = UIFont.systemFont(ofSize: 32) + textLabel.font = .mullvadBig textLabel.textColor = .white textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.adjustsFontForContentSizeCategory = true return textLabel }() let messageLabel: UILabel = { let textLabel = UILabel() - textLabel.font = UIFont.systemFont(ofSize: 17) + textLabel.font = .mullvadTinySemiBold textLabel.textColor = UIColor.white.withAlphaComponent(0.6) textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.adjustsFontForContentSizeCategory = true textLabel.numberOfLines = 0 return textLabel }() @@ -71,9 +73,11 @@ class LoginContentView: UIView { let footerLabel: UILabel = { let textLabel = UILabel() - textLabel.font = UIFont.systemFont(ofSize: 17) + textLabel.font = .mullvadSmall textLabel.textColor = UIColor.white.withAlphaComponent(0.6) textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.adjustsFontForContentSizeCategory = true + textLabel.numberOfLines = 0 textLabel.text = NSLocalizedString( "CREATE_BUTTON_HEADER_LABEL", tableName: "Login", diff --git a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift index 11cb3bcbbf..33d4f8d10b 100644 --- a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift +++ b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift @@ -24,7 +24,8 @@ class OutOfTimeContentView: UIView { value: "Out of time", comment: "" ) - label.font = UIFont.systemFont(ofSize: 32) + label.font = .mullvadLarge + label.adjustsFontForContentSizeCategory = true label.textColor = .white return label }() @@ -33,6 +34,7 @@ class OutOfTimeContentView: UIView { let label = UILabel() label.textColor = .white label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true return label }() @@ -151,7 +153,7 @@ class OutOfTimeContentView: UIView { func setBodyLabelText(_ text: String) { bodyLabel.attributedText = NSAttributedString( markdownString: text, - options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body)) + options: MarkdownStylingOptions(font: .mullvadSmall) ) } } diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift index 01d7afb09c..a41bdd2187 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportReviewViewController.swift @@ -60,10 +60,8 @@ class ProblemReportReviewViewController: UIViewController { textView.setAccessibilityIdentifier(.problemReportAppLogsTextView) textView.translatesAutoresizingMaskIntoConstraints = false textView.isEditable = false - textView.font = UIFont.monospacedSystemFont( - ofSize: UIFont.systemFontSize, - weight: .regular - ) + textView.font = .mullvadSmall + textView.adjustsFontForContentSizeCategory = true textView.backgroundColor = .systemBackground view.addConstrainedSubviews([textView]) { diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift index 005a81bd64..2c341f0557 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportSubmissionOverlayView.swift @@ -156,7 +156,8 @@ class ProblemReportSubmissionOverlayView: UIView { let titleLabel: UILabel = { let textLabel = UILabel() - textLabel.font = UIFont.systemFont(ofSize: 32) + textLabel.font = .mullvadLarge + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = .white textLabel.numberOfLines = 0 return textLabel @@ -300,7 +301,8 @@ class ProblemReportSubmissionOverlayView: UIView { bodyLabelContainer.subviews.forEach { $0.removeFromSuperview() } state.body?.forEach { attributedString in let textLabel = UILabel() - textLabel.font = UIFont.systemFont(ofSize: 17) + textLabel.font = .mullvadSmall + textLabel.adjustsFontForContentSizeCategory = true textLabel.textColor = .white.withAlphaComponent(0.6) textLabel.numberOfLines = 0 textLabel.attributedText = attributedString diff --git a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController+ViewManagement.swift b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController+ViewManagement.swift index c5370188eb..d5434412b0 100644 --- a/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController+ViewManagement.swift +++ b/ios/MullvadVPN/View controllers/ProblemReport/ProblemReportViewController+ViewManagement.swift @@ -28,6 +28,8 @@ extension ProblemReportViewController { func makeSubheaderLabel() -> UILabel { let textLabel = UILabel() textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.font = .mullvadTinySemiBold + textLabel.adjustsFontForContentSizeCategory = true textLabel.numberOfLines = 0 textLabel.textColor = .white textLabel.text = ProblemReportViewModel.subheadLabelText @@ -47,7 +49,8 @@ extension ProblemReportViewController { textField.borderStyle = .none textField.backgroundColor = .white textField.inputAccessoryView = emailAccessoryToolbar - textField.font = UIFont.systemFont(ofSize: 17) + textField.font = .mullvadSmall + textField.adjustsFontForContentSizeCategory = true textField.placeholder = ProblemReportViewModel.emailPlaceholderText return textField } @@ -57,7 +60,8 @@ extension ProblemReportViewController { textView.translatesAutoresizingMaskIntoConstraints = false textView.backgroundColor = .white textView.inputAccessoryView = messageAccessoryToolbar - textView.font = UIFont.systemFont(ofSize: 17) + textView.font = .mullvadSmall + textView.adjustsFontForContentSizeCategory = true textView.placeholder = ProblemReportViewModel.messageTextViewPlaceholder textView.contentInsetAdjustmentBehavior = .never diff --git a/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift b/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift index 1399276784..16dceaf257 100644 --- a/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift +++ b/ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherContentView.swift @@ -34,7 +34,7 @@ final class RedeemVoucherContentView: UIView { private let title: UILabel = { let label = UILabel() - label.font = .preferredFont(forTextStyle: .title1, weight: .bold).withSize(32) + label.font = .mullvadLarge label.text = NSLocalizedString( "REDEEM_VOUCHER_TITLE", tableName: "RedeemVoucher", @@ -43,12 +43,13 @@ final class RedeemVoucherContentView: UIView { ) label.textColor = .white label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true return label }() private let enterVoucherLabel: UILabel = { let label = UILabel() - label.font = .preferredFont(forTextStyle: .body, weight: .semibold).withSize(15) + label.font = .mullvadTinySemiBold label.text = NSLocalizedString( "REDEEM_VOUCHER_INSTRUCTION", @@ -58,12 +59,14 @@ final class RedeemVoucherContentView: UIView { ) label.textColor = .white label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true return label }() private let textField: VoucherTextField = { let textField = VoucherTextField() - textField.font = UIFont.monospacedSystemFont(ofSize: 15, weight: .regular) + textField.font = UIFontMetrics(forTextStyle: .subheadline) + .scaledFont(for: .monospacedSystemFont(ofSize: 15, weight: .regular)) textField.placeholder = Array(repeating: "XXXX", count: 4).joined(separator: "-") textField.placeholderTextColor = .lightGray textField.backgroundColor = .white @@ -72,6 +75,7 @@ final class RedeemVoucherContentView: UIView { textField.autocapitalizationType = .allCharacters textField.returnKeyType = .done textField.autocorrectionType = .no + textField.adjustsFontForContentSizeCategory = true return textField }() @@ -85,8 +89,9 @@ final class RedeemVoucherContentView: UIView { private let statusLabel: UILabel = { let label = UILabel() - label.font = .systemFont(ofSize: 13, weight: .semibold) + label.font = .mullvadMiniSemiBold label.numberOfLines = 2 + label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.textColor = .red label.setContentHuggingPriority(.defaultLow, for: .horizontal) diff --git a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift index 81160dd1cf..01fdc7900b 100644 --- a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift +++ b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift @@ -18,7 +18,8 @@ class RevokedDeviceViewController: UIViewController, RootContainment { private lazy var titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.translatesAutoresizingMaskIntoConstraints = false - titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) + titleLabel.font = .mullvadLarge + titleLabel.adjustsFontForContentSizeCategory = true titleLabel.numberOfLines = 0 titleLabel.textColor = .white titleLabel.text = NSLocalizedString( @@ -33,7 +34,8 @@ class RevokedDeviceViewController: UIViewController, RootContainment { private lazy var bodyLabel: UILabel = { let bodyLabel = UILabel() bodyLabel.translatesAutoresizingMaskIntoConstraints = false - bodyLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold) + bodyLabel.adjustsFontForContentSizeCategory = true + bodyLabel.font = .mullvadSmall bodyLabel.numberOfLines = 0 bodyLabel.textColor = .white bodyLabel.text = NSLocalizedString( @@ -48,7 +50,8 @@ class RevokedDeviceViewController: UIViewController, RootContainment { private lazy var footerLabel: UILabel = { let bodyLabel = UILabel() bodyLabel.translatesAutoresizingMaskIntoConstraints = false - bodyLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold) + bodyLabel.font = .mullvadSmall + bodyLabel.adjustsFontForContentSizeCategory = true bodyLabel.numberOfLines = 0 bodyLabel.textColor = .white bodyLabel.text = NSLocalizedString( diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationCell.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationCell.swift index ba1958998c..a8e1d03cb9 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationCell.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationCell.swift @@ -18,7 +18,8 @@ class LocationCell: UITableViewCell { private let locationLabel: UILabel = { let label = UILabel() - label.font = UIFont.systemFont(ofSize: 16) + label.font = .mullvadSmall + label.adjustsFontForContentSizeCategory = true label.textColor = .white label.lineBreakMode = .byTruncatingTail label.numberOfLines = 1 @@ -34,6 +35,7 @@ class LocationCell: UITableViewCell { private let tickImageView: UIImageView = { let imageView = UIImageView(image: UIImage.tick) + imageView.adjustsImageSizeForAccessibilityContentSizeCategory = true imageView.tintColor = .white return imageView }() @@ -54,6 +56,7 @@ class LocationCell: UITableViewCell { private let collapseButton: UIButton = { let button = UIButton(type: .custom) button.isAccessibilityElement = false + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.tintColor = .white return button }() @@ -165,11 +168,8 @@ class LocationCell: UITableViewCell { statusIndicator.centerXAnchor.constraint(equalTo: tickImageView.centerXAnchor) statusIndicator.centerYAnchor.constraint(equalTo: tickImageView.centerYAnchor) - checkboxButton.pinEdgesToSuperview(PinnableEdges([.top(0), .bottom(0)])) + checkboxButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) checkboxButton.trailingAnchor.constraint(equalTo: locationLabel.leadingAnchor, constant: 14) - checkboxButton.widthAnchor.constraint( - equalToConstant: UIMetrics.contentLayoutMargins.leading + UIMetrics.contentLayoutMargins.trailing + 24 - ) locationLabel.pinEdgesToSuperviewMargins(PinnableEdges([.top(0), .bottom(0)])) locationLabel.leadingAnchor.constraint( diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationSectionHeaderFooterView.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationSectionHeaderFooterView.swift index ec379ea7e6..dcce16c689 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationSectionHeaderFooterView.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationSectionHeaderFooterView.swift @@ -73,6 +73,7 @@ class LocationSectionHeaderFooterView: UIView, UIContentView { nameLabel.textColor = configuration.style.textColor nameLabel.text = configuration.name nameLabel.font = configuration.style.font + nameLabel.adjustsFontForContentSizeCategory = true nameLabel.textAlignment = configuration.style.textAlignment actionButton.isHidden = isActionHidden actionButton.accessibilityIdentifier = nil diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsCell.swift index 569e01be0d..b2cb09788f 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsCell.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsCell.swift @@ -50,6 +50,7 @@ class SettingsCell: UITableViewCell, CustomCellDisclosureHandling { if let image { disclosureImageView.image = image + disclosureImageView.adjustsImageSizeForAccessibilityContentSizeCategory = true disclosureImageView.sizeToFit() accessoryView = disclosureImageView } else { @@ -60,7 +61,8 @@ class SettingsCell: UITableViewCell, CustomCellDisclosureHandling { let titleLabel: UILabel = { let label = UILabel() - label.font = UIFont.systemFont(ofSize: 17) + label.font = .mullvadSmallSemiBold + label.adjustsFontForContentSizeCategory = true label.textColor = UIColor.Cell.titleTextColor label.setContentHuggingPriority(.defaultHigh, for: .horizontal) label.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) @@ -69,7 +71,8 @@ class SettingsCell: UITableViewCell, CustomCellDisclosureHandling { let detailTitleLabel: UILabel = { let label = UILabel() - label.font = UIFont.systemFont(ofSize: 13) + label.font = .mullvadTiny + label.adjustsFontForContentSizeCategory = true label.textColor = UIColor.Cell.detailTextColor label.setContentHuggingPriority(.defaultLow, for: .horizontal) label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) @@ -84,6 +87,7 @@ class SettingsCell: UITableViewCell, CustomCellDisclosureHandling { button.setAccessibilityIdentifier(.infoButton) button.tintColor = .white button.setImage(UIImage.Buttons.info, for: .normal) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.isHidden = true return button }() diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDNSInfoCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDNSInfoCell.swift index 7294528dea..a8b85961f8 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsDNSInfoCell.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsDNSInfoCell.swift @@ -17,6 +17,7 @@ class SettingsDNSInfoCell: UITableViewCell { backgroundColor = .secondaryColor contentView.directionalLayoutMargins = UIMetrics.SettingsCell.layoutMargins + titleLabel.adjustsFontForContentSizeCategory = true titleLabel.translatesAutoresizingMaskIntoConstraints = false titleLabel.textColor = UIColor.Cell.titleTextColor titleLabel.numberOfLines = 0 diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift index b335d686d7..3a4c1c3ae5 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsDNSTextCell.swift @@ -24,7 +24,8 @@ class SettingsDNSTextCell: SettingsCell, UITextFieldDelegate { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - textField.font = UIFont.systemFont(ofSize: 17) + textField.font = .mullvadSmall + textField.adjustsFontForContentSizeCategory = true textField.backgroundColor = .clear textField.textColor = UIColor.TextField.textColor textField.textMargins = UIMetrics.SettingsCell.textFieldContentInsets diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift index fe2a1e0a55..4ad7da0ee1 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift @@ -15,7 +15,8 @@ class SettingsHeaderView: UITableViewHeaderFooterView { let titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.translatesAutoresizingMaskIntoConstraints = false - titleLabel.font = .systemFont(ofSize: 17) + titleLabel.font = .mullvadSmallSemiBold + titleLabel.adjustsFontForContentSizeCategory = true titleLabel.textColor = UIColor.Cell.titleTextColor titleLabel.numberOfLines = 0 return titleLabel @@ -24,6 +25,7 @@ class SettingsHeaderView: UITableViewHeaderFooterView { let infoButton: UIButton = { let button = UIButton(type: .custom) button.setAccessibilityIdentifier(.infoButton) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.tintColor = .white button.setImage(UIImage.Buttons.info, for: .normal) return button @@ -31,6 +33,7 @@ class SettingsHeaderView: UITableViewHeaderFooterView { let collapseButton: UIButton = { let button = UIButton(type: .custom) + button.adjustsImageSizeForAccessibilityContentSizeCategory = true button.setAccessibilityIdentifier(.expandButton) button.tintColor = .white return button diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift index c83b9cae05..8150e2ef8a 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift @@ -219,7 +219,7 @@ final class CustomDNSCellFactory: @preconcurrency CellFactoryProtocol { cell.titleLabel.attributedText = viewModel.customDNSPrecondition.attributedLocalizedDescription( isEditing: isEditing, - preferredFont: .systemFont(ofSize: 14) + preferredFont: .mullvadSmallSemiBold ) } } diff --git a/ios/MullvadVPN/Views/AppButton.swift b/ios/MullvadVPN/Views/AppButton.swift index 73ea4cdc4f..b1a4957de2 100644 --- a/ios/MullvadVPN/Views/AppButton.swift +++ b/ios/MullvadVPN/Views/AppButton.swift @@ -115,7 +115,7 @@ class AppButton: CustomButton { config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { [weak self] attributeContainer in var updatedAttributeContainer = attributeContainer - updatedAttributeContainer.font = UIFont.systemFont(ofSize: 18, weight: .semibold) + updatedAttributeContainer.font = .mullvadSmallSemiBold updatedAttributeContainer.foregroundColor = self?.state.customButtonTitleColor return updatedAttributeContainer } diff --git a/ios/MullvadVPN/Views/CheckboxView.swift b/ios/MullvadVPN/Views/CheckboxView.swift index 5152c98fc5..e4f3667865 100644 --- a/ios/MullvadVPN/Views/CheckboxView.swift +++ b/ios/MullvadVPN/Views/CheckboxView.swift @@ -30,6 +30,8 @@ class CheckboxView: UIView { checkboxSelectedView.pinEdgesToSuperview() checkboxUnselectedView.pinEdgesToSuperview() } + checkboxSelectedView.adjustsImageSizeForAccessibilityContentSizeCategory = true + checkboxUnselectedView.adjustsImageSizeForAccessibilityContentSizeCategory = true } required init?(coder aDecoder: NSCoder) { diff --git a/ios/MullvadVPN/Views/CustomTextView.swift b/ios/MullvadVPN/Views/CustomTextView.swift index bc6df60504..61fddcbee4 100644 --- a/ios/MullvadVPN/Views/CustomTextView.swift +++ b/ios/MullvadVPN/Views/CustomTextView.swift @@ -41,7 +41,7 @@ class CustomTextView: UITextView { override var font: UIFont? { didSet { - placeholderTextLabel.font = font ?? UIFont.preferredFont(forTextStyle: .body) + placeholderTextLabel.font = font ?? .mullvadSmall } } @@ -94,6 +94,7 @@ class CustomTextView: UITextView { placeholderTextLabel.textColor = UIColor.TextField.placeholderTextColor placeholderTextLabel.highlightedTextColor = UIColor.TextField.placeholderTextColor placeholderTextLabel.translatesAutoresizingMaskIntoConstraints = false + placeholderTextLabel.adjustsFontForContentSizeCategory = true placeholderTextLabel.numberOfLines = 0 addSubview(placeholderTextLabel) diff --git a/ios/MullvadVPN/Views/InfoHeaderView.swift b/ios/MullvadVPN/Views/InfoHeaderView.swift index 48db0465bb..403ba7bb27 100644 --- a/ios/MullvadVPN/Views/InfoHeaderView.swift +++ b/ios/MullvadVPN/Views/InfoHeaderView.swift @@ -24,6 +24,7 @@ class InfoHeaderView: UIView, UITextViewDelegate { infoLabel.backgroundColor = .clear infoLabel.attributedText = makeAttributedString() + infoLabel.adjustsFontForContentSizeCategory = true infoLabel.numberOfLines = 0 infoLabel.accessibilityTraits = .link @@ -38,12 +39,12 @@ class InfoHeaderView: UIView, UITextViewDelegate { } private let defaultTextAttributes: [NSAttributedString.Key: Any] = [ - .font: UIFont.systemFont(ofSize: 13), + .font: UIFont.mullvadTiny, .foregroundColor: UIColor.ContentHeading.textColor, ] private let defaultLinkAttributes: [NSAttributedString.Key: Any] = [ - .font: UIFont.boldSystemFont(ofSize: 13), + .font: UIFont.mullvadTiny, .foregroundColor: UIColor.ContentHeading.linkColor, .attachment: "#", ] diff --git a/ios/MullvadVPN/Views/StatusImageView.swift b/ios/MullvadVPN/Views/StatusImageView.swift index e7a19fc15c..752156b0ea 100644 --- a/ios/MullvadVPN/Views/StatusImageView.swift +++ b/ios/MullvadVPN/Views/StatusImageView.swift @@ -45,10 +45,6 @@ class StatusImageView: UIImageView { } } - override var intrinsicContentSize: CGSize { - CGSize(width: 60, height: 60) - } - override init(frame: CGRect) { super.init(frame: frame) image = style.image @@ -58,6 +54,7 @@ class StatusImageView: UIImageView { self.style = style super.init(image: style.image) image = style.image + self.adjustsImageSizeForAccessibilityContentSizeCategory = true setAccessibilityIdentifier(.statusImageView) } |
