summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/SettingsCell.swift
blob: 02d704f50bc1d3990aab58e79f1e5be67051d074 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//
//  SettingsCell.swift
//  MullvadVPN
//
//  Created by pronebird on 22/05/2019.
//  Copyright © 2019 Mullvad VPN AB. All rights reserved.
//

import UIKit

class SettingsCell: UITableViewCell {

    let titleLabel = UILabel()
    let detailTitleLabel = UILabel()

    lazy var customDisclosureIndicator: UIImageView = {
        let disclosureImage = UIImage(named: "IconChevron")?
            .backport_withTintColor(UIColor.Cell.disclosureIndicatorColor, renderingMode: .alwaysOriginal)

        return UIImageView(image: disclosureImage)
    }()


    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        backgroundView = UIView()
        backgroundView?.backgroundColor = UIColor.Cell.backgroundColor

        selectedBackgroundView = UIView()
        selectedBackgroundView?.backgroundColor = UIColor.Cell.selectedAltBackgroundColor

        separatorInset = .zero
        backgroundColor = .clear
        contentView.backgroundColor = .clear

        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.font = UIFont.systemFont(ofSize: 17)
        titleLabel.textColor = UIColor.Cell.titleTextColor

        detailTitleLabel.translatesAutoresizingMaskIntoConstraints = false
        detailTitleLabel.font = UIFont.systemFont(ofSize: 13)
        detailTitleLabel.textColor = UIColor.Cell.detailTextColor

        titleLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        detailTitleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)

        titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
        detailTitleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        contentView.addSubview(titleLabel)
        contentView.addSubview(detailTitleLabel)

        setLayoutMargins()

        NSLayoutConstraint.activate([
            titleLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
            titleLabel.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
            titleLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),

            detailTitleLabel.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: titleLabel.trailingAnchor, multiplier: 1),

            detailTitleLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
            detailTitleLabel.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
            detailTitleLabel.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),
        ])
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func prepareForReuse() {
        super.prepareForReuse()

        setLayoutMargins()
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if #available(iOS 13, *) {
            // no-op
        } else {
            layoutSubviews_iOS12()
        }
    }

    private func setLayoutMargins() {
        // Set layout margins for standard acceessories added into the cell (reorder control, etc..)
        layoutMargins = UIMetrics.settingsCellLayoutMargins

        // Set layout margins for cell content
        contentView.layoutMargins = UIMetrics.settingsCellLayoutMargins
    }

    func setCustomDisclosureIndicator() {
        accessoryType = .none
        accessoryView = customDisclosureIndicator
    }

    func unsetCustomDisclosureIndicator() {
        accessoryView = nil
        accessoryType = .none
    }

    /// On iOS 12, standard edit and reorder controls do not respect layout margins.
    /// This method does layout adjustments to fix that.
    private func layoutSubviews_iOS12() {
        guard isEditing || showsReorderControl else { return }

        var leftOffset: CGFloat = 0
        var rightOffset: CGFloat = 0

        for subview in subviews {
            // Detect the edit control and move it, so that the nested image view is aligned along the left edge of the
            // layout margins.
            if subview.description.starts(with: "<UITableViewCellEditControl"), let imageView = subview.subviews.first {
                let imageOffset = imageView.frame.minX
                var pos = subview.frame.origin
                pos.x = layoutMargins.left - imageOffset
                subview.frame.origin = pos
                leftOffset = pos.x
            }

            // Detect the reorder control and move it, so that its right edge is aligned along the right edge of the
            // layout margins.
            if subview.description.starts(with: "<UITableViewCellReorderControl") {
                var pos = subview.frame.origin
                pos.x -= layoutMargins.right
                subview.frame.origin = pos
                rightOffset = layoutMargins.right
            }
        }

        // Adjust the content view to account for the adjustments to the edit and reorder controls.
        let contentInset = UIEdgeInsets(top: 0, left: leftOffset, bottom: 0, right: rightOffset)
        contentView.frame = contentView.frame.inset(by: contentInset)
    }
}