Dactyloidae/mobile/ios/Client/Frontend/Widgets/ActivityStreamHighlightCell.swift
2026-06-26 21:04:09 -07:00

237 lines
8.9 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
import Shared
import Storage
struct ActivityStreamHighlightCellUX {
static let LabelColor = UIAccessibilityDarkerSystemColorsEnabled() ? UIColor.black : UIColor(rgb: 0x353535)
static let BorderWidth: CGFloat = 0.5
static let CellSideOffset = 20
static let TitleLabelOffset = 2
static let CellTopBottomOffset = 12
static let SiteImageViewSize: CGSize = UIDevice.current.userInterfaceIdiom == .pad ? CGSize(width: 99, height: 120) : CGSize(width: 99, height: 90)
static let StatusIconSize = 12
static let FaviconSize = CGSize(width: 45, height: 45)
static let DescriptionLabelColor = UIColor(rgb: 0x919191)
static let SelectedOverlayColor = UIColor(white: 0.0, alpha: 0.25)
static let CornerRadius: CGFloat = 3
static let BorderColor = UIColor(white: 0, alpha: 0.1)
}
class ActivityStreamHighlightCell: UICollectionViewCell {
fileprivate lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.font = DynamicFontHelper.defaultHelper.MediumSizeHeavyWeightAS
titleLabel.textColor = ActivityStreamHighlightCellUX.LabelColor
titleLabel.textAlignment = .left
titleLabel.numberOfLines = 3
return titleLabel
}()
fileprivate lazy var descriptionLabel: UILabel = {
let descriptionLabel = UILabel()
descriptionLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS
descriptionLabel.textColor = ActivityStreamHighlightCellUX.DescriptionLabelColor
descriptionLabel.textAlignment = .left
descriptionLabel.numberOfLines = 1
return descriptionLabel
}()
fileprivate lazy var domainLabel: UILabel = {
let descriptionLabel = UILabel()
descriptionLabel.font = DynamicFontHelper.defaultHelper.SmallSizeRegularWeightAS
descriptionLabel.textColor = ActivityStreamHighlightCellUX.DescriptionLabelColor
descriptionLabel.textAlignment = .left
descriptionLabel.numberOfLines = 1
descriptionLabel.setContentCompressionResistancePriority(1000, for: UILayoutConstraintAxis.vertical)
return descriptionLabel
}()
lazy var siteImageView: UIImageView = {
let siteImageView = UIImageView()
siteImageView.contentMode = UIViewContentMode.scaleAspectFit
siteImageView.clipsToBounds = true
siteImageView.contentMode = UIViewContentMode.center
siteImageView.layer.cornerRadius = ActivityStreamHighlightCellUX.CornerRadius
siteImageView.layer.borderColor = ActivityStreamHighlightCellUX.BorderColor.cgColor
siteImageView.layer.borderWidth = ActivityStreamHighlightCellUX.BorderWidth
siteImageView.layer.masksToBounds = true
return siteImageView
}()
fileprivate lazy var statusIcon: UIImageView = {
let statusIcon = UIImageView()
statusIcon.contentMode = UIViewContentMode.scaleAspectFit
statusIcon.clipsToBounds = true
statusIcon.layer.cornerRadius = ActivityStreamHighlightCellUX.CornerRadius
return statusIcon
}()
fileprivate lazy var selectedOverlay: UIView = {
let selectedOverlay = UIView()
selectedOverlay.backgroundColor = ActivityStreamHighlightCellUX.SelectedOverlayColor
selectedOverlay.isHidden = true
return selectedOverlay
}()
override var isSelected: Bool {
didSet {
self.selectedOverlay.isHidden = !isSelected
}
}
override init(frame: CGRect) {
super.init(frame: frame)
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
isAccessibilityElement = true
contentView.addSubview(siteImageView)
contentView.addSubview(descriptionLabel)
contentView.addSubview(selectedOverlay)
contentView.addSubview(titleLabel)
contentView.addSubview(statusIcon)
contentView.addSubview(domainLabel)
siteImageView.snp.makeConstraints { make in
make.top.equalTo(contentView)
make.leading.trailing.equalTo(contentView)
make.centerX.equalTo(contentView)
make.height.equalTo(ActivityStreamHighlightCellUX.SiteImageViewSize)
}
selectedOverlay.snp.makeConstraints { make in
make.edges.equalTo(contentView)
}
domainLabel.snp.makeConstraints { make in
make.leading.equalTo(siteImageView)
make.trailing.equalTo(contentView)
make.top.equalTo(siteImageView.snp.bottom).offset(5)
}
titleLabel.snp.makeConstraints { make in
make.leading.equalTo(siteImageView)
make.trailing.equalTo(contentView)
make.top.equalTo(domainLabel.snp.bottom).offset(5)
}
descriptionLabel.snp.makeConstraints { make in
make.leading.equalTo(statusIcon.snp.trailing).offset(ActivityStreamHighlightCellUX.TitleLabelOffset)
make.bottom.equalTo(contentView)
}
statusIcon.snp.makeConstraints { make in
make.size.equalTo(ActivityStreamHighlightCellUX.StatusIconSize)
make.centerY.equalTo(descriptionLabel.snp.centerY)
make.leading.equalTo(siteImageView)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
self.siteImageView.image = nil
contentView.backgroundColor = UIColor.clear
siteImageView.backgroundColor = UIColor.clear
}
func configureWithSite(_ site: Site) {
if let mediaURLStr = site.metadata?.mediaURL,
let mediaURL = URL(string: mediaURLStr) {
self.siteImageView.sd_setImage(with: mediaURL)
self.siteImageView.contentMode = .scaleAspectFill
} else {
let itemURL = site.tileURL
self.siteImageView.setFavicon(forSite: site, onCompletion: { [weak self] (color, url) in
if itemURL == url {
self?.siteImageView.image = self?.siteImageView.image?.createScaled(ActivityStreamHighlightCellUX.FaviconSize)
self?.siteImageView.backgroundColor = color
}
})
self.siteImageView.contentMode = .center
}
self.domainLabel.text = site.tileURL.hostSLD
self.titleLabel.text = site.title.characters.count <= 1 ? site.url : site.title
if let bookmarked = site.bookmarked, bookmarked {
self.descriptionLabel.text = Strings.HighlightBookmarkText
self.statusIcon.image = UIImage(named: "context_bookmark")
} else {
self.descriptionLabel.text = Strings.HighlightVistedText
self.statusIcon.image = UIImage(named: "context_viewed")
}
}
func configureWithPocketStory(_ pocketStory: PocketStory) {
self.siteImageView.sd_setImage(with: pocketStory.imageURL)
self.siteImageView.contentMode = .scaleAspectFill
self.domainLabel.text = pocketStory.domain
self.titleLabel.text = pocketStory.title
self.descriptionLabel.text = Strings.PocketTrendingText
self.statusIcon.image = UIImage(named: "context_pocket")
}
}
struct HighlightIntroCellUX {
static let margin: CGFloat = 20
static let foxImageWidth: CGFloat = 168
}
class HighlightIntroCell: UICollectionViewCell {
lazy var titleLabel: UILabel = {
let textLabel = UILabel()
textLabel.font = DynamicFontHelper.defaultHelper.MediumSizeBoldFontAS
textLabel.textColor = UIColor.black
textLabel.numberOfLines = 1
textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.8
return textLabel
}()
lazy var descriptionLabel: UILabel = {
let label = UILabel()
label.font = DynamicFontHelper.defaultHelper.MediumSizeRegularWeightAS
label.textColor = UIColor.darkGray
label.numberOfLines = 0
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(titleLabel)
contentView.addSubview(descriptionLabel)
titleLabel.text = Strings.HighlightIntroTitle
descriptionLabel.text = Strings.HighlightIntroDescription
let titleInsets = UIEdgeInsets(top: HighlightIntroCellUX.margin, left: 0, bottom: 0, right: 0)
titleLabel.snp.makeConstraints { make in
make.leading.top.trailing.equalTo(self.contentView).inset(titleInsets)
}
descriptionLabel.snp.makeConstraints { make in
make.leading.trailing.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(HighlightIntroCellUX.margin/2)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}