diff --git a/Sources/WireGuardApp/Base.lproj/Localizable.strings b/Sources/WireGuardApp/Base.lproj/Localizable.strings index 204b883..0ba003e 100644 --- a/Sources/WireGuardApp/Base.lproj/Localizable.strings +++ b/Sources/WireGuardApp/Base.lproj/Localizable.strings @@ -17,7 +17,7 @@ "tunnelsListSelectAllButtonTitle" = "Select All"; "tunnelsListDeleteButtonTitle" = "Delete"; "tunnelsListSelectedTitle (%d)" = "%d selected"; -"tunnelListCaptionOnDemand" = "On Demand"; +"tunnelsListOnDemandActiveCellSubTitle" = "On-Demand is enabled"; // Tunnels list menu diff --git a/Sources/WireGuardApp/UI/iOS/View/TunnelListCell.swift b/Sources/WireGuardApp/UI/iOS/View/TunnelListCell.swift index ffccd3f..6fc6984 100644 --- a/Sources/WireGuardApp/UI/iOS/View/TunnelListCell.swift +++ b/Sources/WireGuardApp/UI/iOS/View/TunnelListCell.swift @@ -35,6 +35,18 @@ class TunnelListCell: UITableViewCell { return nameLabel }() + let subTitleLabel: UILabel = { + let subTitleLabel = UILabel() + subTitleLabel.font = UIFont.preferredFont(forTextStyle: .subheadline) + if #available(iOS 13.0, *) { + subTitleLabel.textColor = .secondaryLabel + } else { + subTitleLabel.textColor = .systemGray + } + subTitleLabel.adjustsFontForContentSizeCategory = true + return subTitleLabel + }() + let busyIndicator: UIActivityIndicatorView = { let busyIndicator: UIActivityIndicatorView if #available(iOS 13.0, *) { @@ -53,12 +65,15 @@ class TunnelListCell: UITableViewCell { private var isOnDemandEnabledObservationToken: NSKeyValueObservation? private var hasOnDemandRulesObservationToken: NSKeyValueObservation? + private var subTitleLabelBottomConstraint: NSLayoutConstraint? + private var nameLabelBottomConstraint: NSLayoutConstraint? + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) accessoryType = .disclosureIndicator - for subview in [statusSwitch, busyIndicator, nameLabel] { + for subview in [statusSwitch, busyIndicator, nameLabel, subTitleLabel] { subview.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(subview) } @@ -68,6 +83,11 @@ class TunnelListCell: UITableViewCell { let nameLabelBottomConstraint = contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: nameLabel.bottomAnchor, multiplier: 1) nameLabelBottomConstraint.priority = .defaultLow + self.nameLabelBottomConstraint = nameLabelBottomConstraint + + subTitleLabelBottomConstraint = + contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: subTitleLabel.bottomAnchor, multiplier: 1) + subTitleLabelBottomConstraint?.priority = .defaultLow NSLayoutConstraint.activate([ statusSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), @@ -75,8 +95,13 @@ class TunnelListCell: UITableViewCell { statusSwitch.leadingAnchor.constraint(equalToSystemSpacingAfter: busyIndicator.trailingAnchor, multiplier: 1), nameLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 1), - nameLabelBottomConstraint, nameLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: contentView.layoutMarginsGuide.leadingAnchor, multiplier: 1), + nameLabel.trailingAnchor.constraint(lessThanOrEqualTo: statusSwitch.leadingAnchor), + nameLabelBottomConstraint, + + subTitleLabel.topAnchor.constraint(equalToSystemSpacingBelow: nameLabel.bottomAnchor, multiplier: 0.25), + subTitleLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: contentView.layoutMarginsGuide.leadingAnchor, multiplier: 1), + subTitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: statusSwitch.leadingAnchor), busyIndicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), busyIndicator.leadingAnchor.constraint(equalToSystemSpacingAfter: nameLabel.trailingAnchor, multiplier: 1) @@ -103,6 +128,20 @@ class TunnelListCell: UITableViewCell { onSwitchToggled?(statusSwitch.isOn) } + private func setSubTitleText(_ string: String?) { + if let string = string { + subTitleLabel.text = string + subTitleLabel.isHidden = false + nameLabelBottomConstraint?.isActive = false + subTitleLabelBottomConstraint?.isActive = true + } else { + subTitleLabel.text = nil + subTitleLabel.isHidden = true + subTitleLabelBottomConstraint?.isActive = false + nameLabelBottomConstraint?.isActive = true + } + } + private func update(from tunnel: TunnelContainer?, animated: Bool) { guard let tunnel = tunnel else { reset(animated: animated) @@ -111,8 +150,8 @@ class TunnelListCell: UITableViewCell { let status = tunnel.status let isOnDemandEngaged = tunnel.isActivateOnDemandEnabled - let isSwitchOn = (status == .activating || status == .active || isOnDemandEngaged) - statusSwitch.setOn(isSwitchOn, animated: true) + let shouldSwitchBeOn = ((status != .deactivating && status != .inactive) || isOnDemandEngaged) + statusSwitch.setOn(shouldSwitchBeOn, animated: true) if isOnDemandEngaged && !(status == .activating || status == .active) { statusSwitch.onTintColor = UIColor.systemYellow @@ -120,6 +159,14 @@ class TunnelListCell: UITableViewCell { statusSwitch.onTintColor = UIColor.systemGreen } + statusSwitch.isUserInteractionEnabled = (status == .inactive || status == .active) + + if tunnel.isActivateOnDemandEnabled { + setSubTitleText(tr("tunnelsListOnDemandActiveCellSubTitle")) + } else { + setSubTitleText(nil) + } + if tunnel.hasOnDemandRules { statusSwitch.isUserInteractionEnabled = true } else { @@ -134,6 +181,8 @@ class TunnelListCell: UITableViewCell { } private func reset(animated: Bool) { + setSubTitleText(nil) + statusSwitch.thumbTintColor = nil statusSwitch.setOn(false, animated: animated) statusSwitch.isUserInteractionEnabled = false busyIndicator.stopAnimating()