I've previously made the buttons bigger (easier to tap) and added some padding around their "glass" backgrounds to preserve appearance spec (40 dp diamater). Turns out UIKit doesn't expect us to do that and dims the entire button with some shade of white on tap. The fix was to make the button as small as it appears to the eye.
107 lines
3.7 KiB
Swift
107 lines
3.7 KiB
Swift
//
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import SignalUI
|
|
import SignalServiceKit
|
|
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
|
|
}
|
|
}
|
|
|
|
init(iconName: String) {
|
|
self.iconName = iconName
|
|
super.init(frame: .zero)
|
|
|
|
var configuration: UIButton.Configuration?
|
|
#if compiler(>=6.2)
|
|
if #available(iOS 26, *) {
|
|
configuration = .glass()
|
|
configuration?.imageColorTransformer = UIConfigurationColorTransformer { _ in
|
|
return .Signal.label
|
|
}
|
|
}
|
|
#endif
|
|
if configuration == nil {
|
|
configuration = .gray()
|
|
configuration?.imageColorTransformer = UIConfigurationColorTransformer { _ in
|
|
return UIColor { traitCollection in
|
|
return traitCollection.userInterfaceStyle == .dark ? .ows_gray15 : .ows_gray75
|
|
}
|
|
}
|
|
configuration?.background.backgroundColorTransformer = UIConfigurationColorTransformer { _ in
|
|
return UIColor { traitCollection in
|
|
return traitCollection.userInterfaceStyle == .dark ? .ows_gray65 : .ows_gray02
|
|
}
|
|
}
|
|
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()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
public override 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),
|
|
])
|
|
}
|
|
}
|