mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-31 11:58:40 +09:00
258 lines
9 KiB
Swift
258 lines
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 Foundation
|
|
|
|
struct TopTabsSeparatorUX {
|
|
static let Identifier = "Separator"
|
|
static let Color = UIColor(rgb: 0x3c3c3d)
|
|
static let Width: CGFloat = 1
|
|
}
|
|
|
|
class TopTabsSeparator: UICollectionReusableView {
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
self.backgroundColor = TopTabsSeparatorUX.Color
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
class TopTabsHeaderFooter: UICollectionReusableView {
|
|
let line = UIView()
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
addSubview(line)
|
|
line.backgroundColor = TopTabsSeparatorUX.Color
|
|
}
|
|
|
|
func arrangeLine(_ kind: String) {
|
|
line.snp.removeConstraints()
|
|
switch kind {
|
|
case UICollectionElementKindSectionHeader:
|
|
line.snp.makeConstraints { make in
|
|
make.trailing.equalTo(self)
|
|
}
|
|
case UICollectionElementKindSectionFooter:
|
|
line.snp.makeConstraints { make in
|
|
make.leading.equalTo(self)
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
line.snp.makeConstraints { make in
|
|
make.height.equalTo(TopTabsUX.SeparatorHeight)
|
|
make.width.equalTo(TopTabsUX.SeparatorWidth)
|
|
make.top.equalTo(self).offset(TopTabsUX.SeparatorYOffset)
|
|
}
|
|
}
|
|
|
|
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
|
|
layer.zPosition = CGFloat(layoutAttributes.zIndex)
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
class TopTabCell: UICollectionViewCell {
|
|
enum Style {
|
|
case light
|
|
case dark
|
|
}
|
|
|
|
static let Identifier = "TopTabCellIdentifier"
|
|
static let ShadowOffsetSize: CGFloat = 2 //The shadow is used to hide the tab separator
|
|
|
|
var style: Style = .light {
|
|
didSet {
|
|
if style != oldValue {
|
|
applyStyle(style)
|
|
}
|
|
}
|
|
}
|
|
|
|
var selectedTab = false {
|
|
didSet {
|
|
backgroundColor = selectedTab ? UIColor(rgb: 0xf9f9fa) : UIColor(rgb: 0x272727)
|
|
titleText.textColor = selectedTab ? UIColor(rgb: 0x0c0c0d) : UIColor(rgb: 0xb1b1b3)
|
|
highlightLine.isHidden = !selectedTab
|
|
closeButton.tintColor = selectedTab ? UIColor(rgb: 0x272727) : UIColor(rgb: 0xb1b1b3)
|
|
// restyle if we are in PBM
|
|
if style == .dark && selectedTab {
|
|
backgroundColor = UIColor(rgb: 0x38383D)
|
|
titleText.textColor = UIColor(rgb: 0xf9f9fa)
|
|
closeButton.tintColor = UIColor(rgb: 0xf9f9fa)
|
|
}
|
|
closeButton.backgroundColor = backgroundColor
|
|
closeButton.layer.shadowColor = backgroundColor?.cgColor
|
|
if selectedTab {
|
|
drawShadow()
|
|
}
|
|
}
|
|
}
|
|
|
|
let titleText: UILabel = {
|
|
let titleText = UILabel()
|
|
titleText.textAlignment = NSTextAlignment.left
|
|
titleText.isUserInteractionEnabled = false
|
|
titleText.numberOfLines = 1
|
|
titleText.lineBreakMode = .byCharWrapping
|
|
titleText.font = DynamicFontHelper.defaultHelper.DefaultSmallFont
|
|
return titleText
|
|
}()
|
|
|
|
let favicon: UIImageView = {
|
|
let favicon = UIImageView()
|
|
favicon.layer.cornerRadius = 2.0
|
|
favicon.layer.masksToBounds = true
|
|
return favicon
|
|
}()
|
|
|
|
let closeButton: UIButton = {
|
|
let closeButton = UIButton()
|
|
closeButton.setImage(UIImage.templateImageNamed("menu-CloseTabs"), for: UIControlState())
|
|
closeButton.tintColor = UIColor(rgb: 0xb1b1b3)
|
|
closeButton.imageEdgeInsets = UIEdgeInsets(top: 15, left: TopTabsUX.TabTitlePadding, bottom: 15, right: TopTabsUX.TabTitlePadding)
|
|
closeButton.layer.shadowOpacity = 0.8
|
|
closeButton.layer.masksToBounds = false
|
|
closeButton.layer.shadowOffset = CGSize(width: -TopTabsUX.TabTitlePadding, height: 0)
|
|
return closeButton
|
|
}()
|
|
|
|
let highlightLine: UIView = {
|
|
let line = UIView()
|
|
line.backgroundColor = UIColor(rgb: 0x0066DC)
|
|
line.isHidden = true
|
|
return line
|
|
}()
|
|
|
|
weak var delegate: TopTabCellDelegate?
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
|
|
closeButton.addTarget(self, action: #selector(TopTabCell.closeTab), for: UIControlEvents.touchUpInside)
|
|
|
|
contentView.addSubview(titleText)
|
|
contentView.addSubview(closeButton)
|
|
contentView.addSubview(favicon)
|
|
contentView.addSubview(highlightLine)
|
|
|
|
favicon.snp.makeConstraints { make in
|
|
make.centerY.equalTo(self).offset(TopTabsUX.TabNudge)
|
|
make.size.equalTo(TabTrayControllerUX.FaviconSize)
|
|
make.leading.equalTo(self).offset(TopTabsUX.TabTitlePadding)
|
|
}
|
|
titleText.snp.makeConstraints { make in
|
|
make.centerY.equalTo(self)
|
|
make.height.equalTo(self)
|
|
make.trailing.equalTo(closeButton.snp.leading).offset(TopTabsUX.TabTitlePadding)
|
|
make.leading.equalTo(favicon.snp.trailing).offset(TopTabsUX.TabTitlePadding)
|
|
}
|
|
closeButton.snp.makeConstraints { make in
|
|
make.centerY.equalTo(self).offset(TopTabsUX.TabNudge)
|
|
make.height.equalTo(self)
|
|
make.width.equalTo(self.snp.height).offset(-TopTabsUX.TabTitlePadding)
|
|
make.trailing.equalTo(self.snp.trailing)
|
|
}
|
|
highlightLine.snp.makeConstraints { make in
|
|
make.top.equalTo(self)
|
|
make.leading.equalTo(self).offset(-TopTabCell.ShadowOffsetSize)
|
|
make.trailing.equalTo(self).offset(TopTabCell.ShadowOffsetSize)
|
|
make.height.equalTo(TopTabsUX.HighlightLineWidth)
|
|
}
|
|
|
|
self.clipsToBounds = false
|
|
|
|
applyStyle(style)
|
|
}
|
|
|
|
fileprivate func applyStyle(_ style: Style) {
|
|
switch style {
|
|
case Style.light:
|
|
titleText.textColor = UIColor.darkText
|
|
backgroundColor = UIConstants.AppBackgroundColor
|
|
highlightLine.backgroundColor = UIColor(rgb: 0x0066DC)
|
|
case Style.dark:
|
|
titleText.textColor = UIColor.lightText
|
|
backgroundColor = UIColor(rgb: 0x38383D)
|
|
highlightLine.backgroundColor = UIColor(rgb: 0x9400ff)
|
|
}
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func prepareForReuse() {
|
|
super.prepareForReuse()
|
|
self.layer.shadowOpacity = 0
|
|
}
|
|
|
|
func closeTab() {
|
|
delegate?.tabCellDidClose(self)
|
|
}
|
|
|
|
// When a tab is selected the shadow prevents the tab separators from showing.
|
|
func drawShadow() {
|
|
self.layer.masksToBounds = false
|
|
self.layer.shadowColor = backgroundColor?.cgColor
|
|
self.layer.shadowOpacity = 1
|
|
self.layer.shadowRadius = 0
|
|
|
|
self.layer.shadowPath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.frame.size.width + (TopTabCell.ShadowOffsetSize * 2), height: self.frame.size.height), cornerRadius: 0).cgPath
|
|
self.layer.shadowOffset = CGSize(width: -TopTabCell.ShadowOffsetSize, height: 0)
|
|
}
|
|
|
|
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
|
|
layer.zPosition = CGFloat(layoutAttributes.zIndex)
|
|
}
|
|
}
|
|
|
|
class TopTabFader: UIView {
|
|
lazy var hMaskLayer: CAGradientLayer = {
|
|
let innerColor: CGColor = UIColor(white: 1, alpha: 1.0).cgColor
|
|
let outerColor: CGColor = UIColor(white: 1, alpha: 0.0).cgColor
|
|
let hMaskLayer = CAGradientLayer()
|
|
hMaskLayer.colors = [outerColor, innerColor, innerColor, outerColor]
|
|
hMaskLayer.locations = [0.00, 0.005, 0.995, 1.0]
|
|
hMaskLayer.startPoint = CGPoint(x: 0, y: 0.5)
|
|
hMaskLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
|
|
hMaskLayer.anchorPoint = CGPoint.zero
|
|
return hMaskLayer
|
|
}()
|
|
|
|
init() {
|
|
super.init(frame: CGRect.zero)
|
|
layer.mask = hMaskLayer
|
|
}
|
|
|
|
internal override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
|
|
let widthA = NSNumber(value: Float(CGFloat(8) / frame.width))
|
|
let widthB = NSNumber(value: Float(1 - CGFloat(8) / frame.width))
|
|
|
|
hMaskLayer.locations = [0.00, widthA, widthB, 1.0]
|
|
hMaskLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
}
|
|
|
|
class TopTabsViewLayoutAttributes: UICollectionViewLayoutAttributes {
|
|
|
|
override func isEqual(_ object: Any?) -> Bool {
|
|
guard let object = object as? TopTabsViewLayoutAttributes else {
|
|
return false
|
|
}
|
|
return super.isEqual(object)
|
|
}
|
|
}
|