Signal-iOS/Signal/ConversationView/ConversationScrollButton.swift
Igor Solomennikov e4c3b8758d
Fix unexpected highlighted area under "scroll down" button in chat on iOS 26.
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.
2025-09-16 17:21:26 -07:00

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),
])
}
}