diff options
| author | mojganii <mojgan.jelodar@codic.se> | 2024-03-15 12:04:21 +0100 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2024-04-05 09:34:32 +0200 |
| commit | 711ffc84de5f3f88ca9cc4344494d1c47e39d0d6 (patch) | |
| tree | 3cc774dfd62e2f4d1bcc252244faa8087b2e0c04 | |
| parent | ad89a992ba49996eee751b7baa257bab0daa0517 (diff) | |
| download | mullvadvpn-711ffc84de5f3f88ca9cc4344494d1c47e39d0d6.tar.xz mullvadvpn-711ffc84de5f3f88ca9cc4344494d1c47e39d0d6.zip | |
Implement addLocationCell
4 files changed, 227 insertions, 22 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 41411f85d4..f14b01f8ca 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -825,6 +825,8 @@ F0164ED12B4F2DCB0020268D /* AccessMethodIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164ED02B4F2DCB0020268D /* AccessMethodIterator.swift */; }; F028A56A2A34D4E700C0CAA3 /* RedeemVoucherViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028A5692A34D4E700C0CAA3 /* RedeemVoucherViewController.swift */; }; F028A56C2A34D8E600C0CAA3 /* AddCreditSucceededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028A56B2A34D8E600C0CAA3 /* AddCreditSucceededViewController.swift */; }; + F02F41A42B9723AF00625A4F /* AddLocationCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02F419E2B9723AF00625A4F /* AddLocationCellViewModel.swift */; }; + F02F41A52B9723AF00625A4F /* AddLocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02F419F2B9723AF00625A4F /* AddLocationCell.swift */; }; F03580252A13842C00E5DAFD /* IncreasedHitButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */; }; F04413612BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; F04413622BA45CE30018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; }; @@ -1981,6 +1983,8 @@ F0164ED02B4F2DCB0020268D /* AccessMethodIterator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessMethodIterator.swift; sourceTree = "<group>"; }; F028A5692A34D4E700C0CAA3 /* RedeemVoucherViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedeemVoucherViewController.swift; sourceTree = "<group>"; }; F028A56B2A34D8E600C0CAA3 /* AddCreditSucceededViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddCreditSucceededViewController.swift; sourceTree = "<group>"; }; + F02F419E2B9723AF00625A4F /* AddLocationCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddLocationCellViewModel.swift; sourceTree = "<group>"; }; + F02F419F2B9723AF00625A4F /* AddLocationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddLocationCell.swift; sourceTree = "<group>"; }; F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncreasedHitButton.swift; sourceTree = "<group>"; }; F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomListLocationNodeBuilder.swift; sourceTree = "<group>"; }; F04F95A02B21D24400431E08 /* shadowsocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shadowsocks.h; sourceTree = "<group>"; }; @@ -3508,6 +3512,8 @@ isa = PBXGroup; children = ( 7A6389D72B7E3BD6008E77E1 /* AddCustomListCoordinator.swift */, + F02F419F2B9723AF00625A4F /* AddLocationCell.swift */, + F02F419E2B9723AF00625A4F /* AddLocationCellViewModel.swift */, 7A6389D22B7E3BD6008E77E1 /* CustomListCellConfiguration.swift */, 7A6389D42B7E3BD6008E77E1 /* CustomListDataSourceConfiguration.swift */, 7A6389DA2B7E3BD6008E77E1 /* CustomListInteractor.swift */, @@ -5179,6 +5185,7 @@ 582BB1B1229569620055B6EF /* UINavigationBar+Appearance.swift in Sources */, 7A9FA1442A2E3FE5000B728D /* CheckableSettingsCell.swift in Sources */, 58ACF6492655365700ACE4B7 /* VPNSettingsViewController.swift in Sources */, + F02F41A52B9723AF00625A4F /* AddLocationCell.swift in Sources */, 7ABE318D2A1CDD4500DF4963 /* UIFont+Weight.swift in Sources */, 58C774BE29A7A249003A1A56 /* CustomNavigationController.swift in Sources */, E1FD0DF528AA7CE400299DB4 /* StatusActivityView.swift in Sources */, @@ -5433,6 +5440,7 @@ 7A6389DB2B7E3BD6008E77E1 /* CustomListCellConfiguration.swift in Sources */, F09A297C2A9F8A9B00EA3B6F /* VoucherTextField.swift in Sources */, 7A5869B72B56B41500640D27 /* IPOverrideTextViewController.swift in Sources */, + F02F41A42B9723AF00625A4F /* AddLocationCellViewModel.swift in Sources */, 58ACF64B26553C3F00ACE4B7 /* SettingsSwitchCell.swift in Sources */, 7AF9BE952A40461100DBFEDB /* RelayFilterView.swift in Sources */, 7A09C98129D99215000C2CAC /* String+FuzzyMatch.swift in Sources */, diff --git a/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 02691892fe..0000000000 --- a/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,22 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "173f567a2dfec11d74588eea82cecea555bdc0bc", - "version" : "1.4.0" - } - }, - { - "identity" : "wireguard-apple", - "kind" : "remoteSourceControl", - "location" : "https://github.com/mullvad/wireguard-apple.git", - "state" : { - "revision" : "11a00c20dc03f2751db47e94f585c0778c7bde82" - } - } - ], - "version" : 2 -} diff --git a/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCell.swift b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCell.swift new file mode 100644 index 0000000000..e0094f0a9a --- /dev/null +++ b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCell.swift @@ -0,0 +1,204 @@ +// +// AddLocationCell.swift +// MullvadVPN +// +// Created by Mojgan on 2024-02-29. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import UIKit + +protocol AddLocationCellDelegate: AnyObject { + func toggleExpanding(cell: AddLocationCell) + func toggleSelection(cell: AddLocationCell) +} + +class AddLocationCell: UITableViewCell { + weak var delegate: AddLocationCellDelegate? + + private let chevronDown = UIImage(resource: .iconChevronDown) + private let chevronUp = UIImage(resource: .iconChevronUp) + + private let locationLabel: UILabel = { + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 17) + label.textColor = .white + label.numberOfLines = .zero + label.lineBreakStrategy = [] + return label + }() + + private let checkboxButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(systemName: "checkmark.square.fill"), for: .selected) + button.setImage(UIImage(systemName: "square"), for: .normal) + button.tintColor = .white + return button + }() + + private let collapseButton: UIButton = { + let button = UIButton(type: .custom) + button.accessibilityIdentifier = .collapseButton + button.isAccessibilityElement = false + button.tintColor = .white + return button + }() + + var isExpanded = false { + didSet { + updateCollapseImage() + updateAccessibilityCustomActions() + } + } + + var showsCollapseControl = false { + didSet { + collapseButton.isHidden = !showsCollapseControl + updateAccessibilityCustomActions() + } + } + + override var indentationLevel: Int { + didSet { + updateBackgroundColor() + setLayoutMargins() + } + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupCell() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setLayoutMargins() { + let indentation = CGFloat(indentationLevel) * indentationWidth + + var contentMargins = UIMetrics.locationCellLayoutMargins + contentMargins.leading += indentation + + contentView.directionalLayoutMargins = contentMargins + } + + private func setupCell() { + indentationWidth = UIMetrics.TableView.cellIndentationWidth + + backgroundColor = .clear + contentView.backgroundColor = .clear + + backgroundView = UIView() + + collapseButton.addTarget(self, action: #selector(handleCollapseButton(_:)), for: .touchUpInside) + checkboxButton.addTarget(self, action: #selector(toggleCheckboxButton(_:)), for: .touchUpInside) + + contentView.addConstrainedSubviews([checkboxButton, locationLabel, collapseButton]) { + checkboxButton.pinEdgeToSuperviewMargin(.leading(.zero)) + checkboxButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) + checkboxButton.widthAnchor + .constraint( + equalToConstant: 44.0 + ) + checkboxButton.heightAnchor.constraint(equalTo: checkboxButton.widthAnchor, multiplier: 1, constant: 0) + + locationLabel.leadingAnchor.constraint( + equalTo: checkboxButton.trailingAnchor, + constant: 12 + ) + + locationLabel.trailingAnchor.constraint(lessThanOrEqualTo: collapseButton.leadingAnchor) + .withPriority(.defaultHigh) + locationLabel.pinEdgesToSuperviewMargins(PinnableEdges([.top(.zero), .bottom(.zero)])) + + collapseButton.widthAnchor + .constraint( + equalToConstant: UIMetrics.contentLayoutMargins.leading + UIMetrics + .contentLayoutMargins.trailing + 24.0 + ) + collapseButton.pinEdgesToSuperviewMargins(.all().excluding(.leading)) + } + + updateCollapseImage() + updateAccessibilityCustomActions() + updateBackgroundColor() + setLayoutMargins() + } + + private func updateBackgroundColor() { + backgroundView?.backgroundColor = backgroundColorForIdentationLevel() + } + + private func backgroundColorForIdentationLevel() -> UIColor { + switch indentationLevel { + case 1: + return UIColor.Cell.Background.indentationLevelOne + case 2: + return UIColor.Cell.Background.indentationLevelTwo + case 3: + return UIColor.Cell.Background.indentationLevelThree + default: + return UIColor.Cell.Background.normal + } + } + + private func updateCollapseImage() { + let image = isExpanded ? chevronUp : chevronDown + collapseButton.setImage(image, for: .normal) + } + + private func updateAccessibilityCustomActions() { + if showsCollapseControl { + let actionName = isExpanded + ? NSLocalizedString( + "ADD_LOCATIONS_COLLAPSE_ACCESSIBILITY_ACTION", + tableName: "AddLocationsLocation", + value: "Collapse location", + comment: "" + ) + : NSLocalizedString( + "ADD_LOCATIONS_EXPAND_ACCESSIBILITY_ACTION", + tableName: "AddLocationsLocation", + value: "Expand location", + comment: "" + ) + + accessibilityCustomActions = [ + UIAccessibilityCustomAction( + name: actionName, + target: self, + selector: #selector(toggleCollapseAccessibilityAction) + ), + ] + } else { + accessibilityCustomActions = nil + } + } + + // MARK: - actions + + @objc private func handleCollapseButton(_ sender: UIControl) { + delegate?.toggleExpanding(cell: self) + } + + @objc private func toggleCollapseAccessibilityAction() -> Bool { + delegate?.toggleExpanding(cell: self) + return true + } + + @objc private func toggleCheckboxButton(_ sender: UIControl) { + delegate?.toggleSelection(cell: self) + } +} + +extension AddLocationCell { + func configure(item: AddLocationCellViewModel) { + accessibilityIdentifier = item.node.name + locationLabel.text = item.node.name + showsCollapseControl = !item.node.children.isEmpty + isExpanded = item.node.showsChildren + checkboxButton.isSelected = item.isSelected + checkboxButton.tintColor = item.isSelected ? .successColor : .white + } +} diff --git a/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCellViewModel.swift b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCellViewModel.swift new file mode 100644 index 0000000000..ffc06aea74 --- /dev/null +++ b/ios/MullvadVPN/Coordinators/CustomLists/AddLocationCellViewModel.swift @@ -0,0 +1,15 @@ +// +// AddLocationCellViewModel.swift +// MullvadVPN +// +// Created by Mojgan on 2024-03-04. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +struct AddLocationCellViewModel: Hashable { + let node: LocationNode + var indentationLevel = 0 + var isSelected: Bool +} |
