124 lines
4.1 KiB
Swift
124 lines
4.1 KiB
Swift
//
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import SignalServiceKit
|
|
import SignalUI
|
|
public import UIKit
|
|
|
|
public class ConversationScrollButton: UIButton {
|
|
|
|
let iconName: String
|
|
|
|
var unreadCount: UInt = 0 {
|
|
didSet {
|
|
unreadCountLabel.text = String.localizedStringWithFormat("%u", unreadCount)
|
|
unreadBadge.isHidden = unreadCount == 0
|
|
}
|
|
}
|
|
|
|
var badgeTintColor: UIColor! {
|
|
get { unreadBadge.backgroundColor ?? UIColor.Signal.accent }
|
|
set { unreadBadge.backgroundColor = newValue ?? UIColor.Signal.accent }
|
|
}
|
|
|
|
init(iconName: String) {
|
|
self.iconName = iconName
|
|
super.init(frame: .zero)
|
|
|
|
var configuration: UIButton.Configuration?
|
|
if #available(iOS 26, *) {
|
|
configuration = .glass()
|
|
}
|
|
if configuration == nil {
|
|
configuration = .gray()
|
|
configuration?.baseForegroundColor = UIColor(
|
|
light: .ows_gray75,
|
|
dark: .ows_gray15,
|
|
)
|
|
configuration?.baseBackgroundColor = UIColor(
|
|
light: .ows_gray02,
|
|
dark: .ows_gray65,
|
|
)
|
|
if #available(iOS 18, *) {
|
|
configuration?.background.shadowProperties.offset = CGSize(width: 0, height: 4)
|
|
configuration?.background.shadowProperties.color = .black
|
|
configuration?.background.shadowProperties.radius = 12
|
|
configuration?.background.shadowProperties.opacity = 0.3
|
|
}
|
|
}
|
|
configuration?.cornerStyle = .capsule
|
|
configuration?.image = UIImage(named: iconName)
|
|
self.configuration = configuration
|
|
|
|
addUnreadLabel()
|
|
}
|
|
|
|
override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
super.traitCollectionDidChange(previousTraitCollection)
|
|
|
|
if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
|
|
applyUnreadBadgeStroke()
|
|
}
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override public var intrinsicContentSize: CGSize {
|
|
.square(ConversationScrollButton.circleDiameter)
|
|
}
|
|
|
|
private class var circleDiameter: CGFloat { 40 }
|
|
|
|
private lazy var unreadCountLabel: UILabel = {
|
|
let label = UILabel()
|
|
label.font = .dynamicTypeFootnoteClamped.semibold()
|
|
label.textColor = .white
|
|
label.textAlignment = .center
|
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
return label
|
|
}()
|
|
|
|
private lazy var unreadBadge: UIView = {
|
|
let view = PillView()
|
|
view.isUserInteractionEnabled = false
|
|
view.clipsToBounds = true
|
|
view.backgroundColor = .Signal.accent
|
|
view.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
view.addSubview(unreadCountLabel)
|
|
NSLayoutConstraint.activate([
|
|
unreadCountLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 6),
|
|
unreadCountLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
|
unreadCountLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 2),
|
|
unreadCountLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
|
view.widthAnchor.constraint(greaterThanOrEqualTo: view.heightAnchor, multiplier: 1),
|
|
])
|
|
|
|
return view
|
|
}()
|
|
|
|
private func addUnreadLabel() {
|
|
let pillViewOverlap: CGFloat = 8 // how much unread badge pill overlaps circle
|
|
addSubview(unreadBadge)
|
|
NSLayoutConstraint.activate([
|
|
unreadBadge.centerXAnchor.constraint(equalTo: centerXAnchor),
|
|
unreadBadge.bottomAnchor.constraint(equalTo: topAnchor, constant: pillViewOverlap),
|
|
])
|
|
|
|
applyUnreadBadgeStroke()
|
|
}
|
|
|
|
private func applyUnreadBadgeStroke() {
|
|
let strokeColor = switch traitCollection.userInterfaceStyle {
|
|
case .dark: UIColor(white: 1, alpha: 0.1)
|
|
default: UIColor(white: 0, alpha: 0.1)
|
|
}
|
|
unreadBadge.layer.borderWidth = 1
|
|
unreadBadge.layer.borderColor = strokeColor.cgColor
|
|
}
|
|
}
|