mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-23 21:03:08 +09:00
263 lines
9.6 KiB
Swift
263 lines
9.6 KiB
Swift
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import UIKit
|
|
|
|
struct TwoLineCellUX {
|
|
static let ImageSize: CGFloat = 29
|
|
static let ImageCornerRadius: CGFloat = 8
|
|
static let BorderViewMargin: CGFloat = 16
|
|
static let BadgeSize: CGFloat = 16
|
|
static let BadgeMargin: CGFloat = 16
|
|
static let BorderFrameSize: CGFloat = 32
|
|
static let TextColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x333333)
|
|
static let DetailTextColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.darkGray : UIColor.gray
|
|
static let DetailTextTopMargin: CGFloat = 0
|
|
}
|
|
|
|
class TwoLineTableViewCell: UITableViewCell {
|
|
fileprivate let twoLineHelper = TwoLineCellHelper()
|
|
|
|
let _textLabel = UILabel()
|
|
let _detailTextLabel = UILabel()
|
|
|
|
// Override the default labels with our own to disable default UITableViewCell label behaviours like dynamic type
|
|
override var textLabel: UILabel? {
|
|
return _textLabel
|
|
}
|
|
|
|
override var detailTextLabel: UILabel? {
|
|
return _detailTextLabel
|
|
}
|
|
|
|
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
|
|
super.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: reuseIdentifier)
|
|
|
|
contentView.addSubview(_textLabel)
|
|
contentView.addSubview(_detailTextLabel)
|
|
|
|
twoLineHelper.setUpViews(self, textLabel: textLabel!, detailTextLabel: detailTextLabel!, imageView: imageView!)
|
|
|
|
indentationWidth = 0
|
|
layoutMargins = UIEdgeInsets.zero
|
|
|
|
separatorInset = UIEdgeInsets(top: 0, left: TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin, bottom: 0, right: 0)
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
twoLineHelper.layoutSubviews()
|
|
}
|
|
|
|
override func prepareForReuse() {
|
|
super.prepareForReuse()
|
|
self.textLabel!.alpha = 1
|
|
self.imageView!.alpha = 1
|
|
self.selectionStyle = .default
|
|
separatorInset = UIEdgeInsets(top: 0, left: TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin, bottom: 0, right: 0)
|
|
twoLineHelper.setupDynamicFonts()
|
|
}
|
|
|
|
// Save background color on UITableViewCell "select" because it disappears in the default behavior
|
|
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
|
let color = imageView?.backgroundColor
|
|
super.setHighlighted(highlighted, animated: animated)
|
|
imageView?.backgroundColor = color
|
|
}
|
|
|
|
// Save background color on UITableViewCell "select" because it disappears in the default behavior
|
|
override func setSelected(_ selected: Bool, animated: Bool) {
|
|
let color = imageView?.backgroundColor
|
|
super.setSelected(selected, animated: animated)
|
|
imageView?.backgroundColor = color
|
|
}
|
|
|
|
func setRightBadge(_ badge: UIImage?) {
|
|
if let badge = badge {
|
|
self.accessoryView = UIImageView(image: badge)
|
|
} else {
|
|
self.accessoryView = nil
|
|
}
|
|
twoLineHelper.hasRightBadge = badge != nil
|
|
}
|
|
|
|
func setLines(_ text: String?, detailText: String?) {
|
|
twoLineHelper.setLines(text, detailText: detailText)
|
|
}
|
|
|
|
func mergeAccessibilityLabels(_ views: [AnyObject?]? = nil) {
|
|
twoLineHelper.mergeAccessibilityLabels(views)
|
|
}
|
|
}
|
|
|
|
class SiteTableViewCell: TwoLineTableViewCell {
|
|
let borderView = UIView()
|
|
|
|
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
|
|
super.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: reuseIdentifier)
|
|
twoLineHelper.setUpViews(self, textLabel: textLabel!, detailTextLabel: detailTextLabel!, imageView: imageView!)
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
twoLineHelper.layoutSubviews()
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
class TwoLineHeaderFooterView: UITableViewHeaderFooterView {
|
|
fileprivate let twoLineHelper = TwoLineCellHelper()
|
|
|
|
// UITableViewHeaderFooterView includes textLabel and detailTextLabel, so we can't override
|
|
// them. Unfortunately, they're also used in ways that interfere with us just using them: I get
|
|
// hard crashes in layout if I just use them; it seems there's a battle over adding to the
|
|
// contentView. So we add our own members, and cover up the other ones.
|
|
let _textLabel = UILabel()
|
|
let _detailTextLabel = UILabel()
|
|
|
|
let imageView = UIImageView()
|
|
|
|
// Yes, this is strange.
|
|
override var textLabel: UILabel? {
|
|
return _textLabel
|
|
}
|
|
|
|
// Yes, this is strange.
|
|
override var detailTextLabel: UILabel? {
|
|
return _detailTextLabel
|
|
}
|
|
|
|
override init(reuseIdentifier: String?) {
|
|
super.init(reuseIdentifier: reuseIdentifier)
|
|
twoLineHelper.setUpViews(self, textLabel: _textLabel, detailTextLabel: _detailTextLabel, imageView: imageView)
|
|
|
|
contentView.addSubview(_textLabel)
|
|
contentView.addSubview(_detailTextLabel)
|
|
contentView.addSubview(imageView)
|
|
|
|
layoutMargins = UIEdgeInsets.zero
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
twoLineHelper.layoutSubviews()
|
|
}
|
|
|
|
override func prepareForReuse() {
|
|
super.prepareForReuse()
|
|
twoLineHelper.setupDynamicFonts()
|
|
}
|
|
|
|
func mergeAccessibilityLabels(_ views: [AnyObject?]? = nil) {
|
|
twoLineHelper.mergeAccessibilityLabels(views)
|
|
}
|
|
}
|
|
|
|
private class TwoLineCellHelper {
|
|
weak var container: UIView?
|
|
var textLabel: UILabel!
|
|
var detailTextLabel: UILabel!
|
|
var imageView: UIImageView!
|
|
var hasRightBadge: Bool = false
|
|
|
|
// TODO: Not ideal. We should figure out a better way to get this initialized.
|
|
func setUpViews(_ container: UIView, textLabel: UILabel, detailTextLabel: UILabel, imageView: UIImageView) {
|
|
self.container = container
|
|
self.textLabel = textLabel
|
|
self.detailTextLabel = detailTextLabel
|
|
self.imageView = imageView
|
|
|
|
if let headerView = self.container as? UITableViewHeaderFooterView {
|
|
headerView.contentView.backgroundColor = UIColor.clear
|
|
} else {
|
|
self.container?.backgroundColor = UIColor.clear
|
|
}
|
|
|
|
textLabel.textColor = TwoLineCellUX.TextColor
|
|
detailTextLabel.textColor = TwoLineCellUX.DetailTextColor
|
|
setupDynamicFonts()
|
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
imageView.layer.cornerRadius = 6 //hmm
|
|
imageView.layer.masksToBounds = true
|
|
}
|
|
|
|
func setupDynamicFonts() {
|
|
textLabel.font = DynamicFontHelper.defaultHelper.DeviceFontHistoryPanel
|
|
detailTextLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS
|
|
}
|
|
|
|
func layoutSubviews() {
|
|
guard let container = self.container else {
|
|
return
|
|
}
|
|
let height = container.frame.height
|
|
let textLeft = TwoLineCellUX.ImageSize + 2 * TwoLineCellUX.BorderViewMargin
|
|
let textLabelHeight = textLabel.intrinsicContentSize.height
|
|
let detailTextLabelHeight = detailTextLabel.intrinsicContentSize.height
|
|
var contentHeight = textLabelHeight
|
|
if detailTextLabelHeight > 0 {
|
|
contentHeight += detailTextLabelHeight + TwoLineCellUX.DetailTextTopMargin
|
|
}
|
|
|
|
let textRightInset: CGFloat = hasRightBadge ? (TwoLineCellUX.BadgeSize + TwoLineCellUX.BadgeMargin) : 0
|
|
|
|
imageView.frame = CGRect(x: TwoLineCellUX.BorderViewMargin, y: (height - TwoLineCellUX.ImageSize) / 2, width: TwoLineCellUX.ImageSize, height: TwoLineCellUX.ImageSize)
|
|
textLabel.frame = CGRect(x: textLeft, y: (height - contentHeight) / 2,
|
|
width: container.frame.width - textLeft - TwoLineCellUX.BorderViewMargin - textRightInset, height: textLabelHeight)
|
|
detailTextLabel.frame = CGRect(x: textLeft, y: textLabel.frame.maxY + TwoLineCellUX.DetailTextTopMargin,
|
|
width: container.frame.width - textLeft - TwoLineCellUX.BorderViewMargin - textRightInset, height: detailTextLabelHeight)
|
|
}
|
|
|
|
func setLines(_ text: String?, detailText: String?) {
|
|
if text?.isEmpty ?? true {
|
|
textLabel.text = detailText
|
|
detailTextLabel.text = nil
|
|
} else {
|
|
textLabel.text = text
|
|
detailTextLabel.text = detailText
|
|
}
|
|
}
|
|
|
|
func mergeAccessibilityLabels(_ labels: [AnyObject?]?) {
|
|
let labels = labels ?? [textLabel, imageView, detailTextLabel]
|
|
|
|
let label = labels.map({ (label: AnyObject?) -> NSAttributedString? in
|
|
var label = label
|
|
if let view = label as? UIView {
|
|
label = view.value(forKey: "accessibilityLabel") as (AnyObject?)
|
|
}
|
|
|
|
if let attrString = label as? NSAttributedString {
|
|
return attrString
|
|
} else if let string = label as? String {
|
|
return NSAttributedString(string: string)
|
|
} else {
|
|
return nil
|
|
}
|
|
}).filter({
|
|
$0 != nil
|
|
}).reduce(NSMutableAttributedString(string: ""), {
|
|
if $0.length > 0 {
|
|
$0.append(NSAttributedString(string: ", "))
|
|
}
|
|
$0.append($1!)
|
|
return $0
|
|
})
|
|
|
|
container?.isAccessibilityElement = true
|
|
container?.setValue(NSAttributedString(attributedString: label), forKey: "accessibilityLabel")
|
|
}
|
|
}
|