• new background color for quoted messages. • new colors for buttons in chat message bubbles. Also cleaned up Theme and UIColor extension.
182 lines
5.5 KiB
Swift
182 lines
5.5 KiB
Swift
//
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import SignalServiceKit
|
|
public import SignalUI
|
|
|
|
public class CVComponentBottomButtons: CVComponentBase, CVComponent {
|
|
|
|
public var componentKey: CVComponentKey { .bottomButtons }
|
|
|
|
private let bottomButtonsState: CVComponentState.BottomButtons
|
|
|
|
typealias Action = CVMessageAction
|
|
fileprivate var actions: [Action] { bottomButtonsState.actions }
|
|
|
|
init(itemModel: CVItemModel, bottomButtonsState: CVComponentState.BottomButtons) {
|
|
self.bottomButtonsState = bottomButtonsState
|
|
|
|
super.init(itemModel: itemModel)
|
|
}
|
|
|
|
public func buildComponentView(componentDelegate: CVComponentDelegate) -> CVComponentView {
|
|
CVComponentViewBottomButtons()
|
|
}
|
|
|
|
public func configureForRendering(
|
|
componentView componentViewParam: CVComponentView,
|
|
cellMeasurement: CVCellMeasurement,
|
|
componentDelegate: CVComponentDelegate,
|
|
) {
|
|
guard let componentView = componentViewParam as? CVComponentViewBottomButtons else {
|
|
owsFailDebug("Unexpected componentView.")
|
|
componentViewParam.reset()
|
|
return
|
|
}
|
|
|
|
componentView.reset()
|
|
|
|
var subviews = [UIView]()
|
|
for action in actions {
|
|
let buttonView = CVMessageActionButton(action: action)
|
|
if isIncoming {
|
|
if conversationStyle.hasWallpaper {
|
|
buttonView.backgroundColor = .Signal.MaterialBase.button
|
|
} else {
|
|
buttonView.backgroundColor = .Signal.LightBase.button
|
|
}
|
|
buttonView.textColor = .Signal.label
|
|
} else {
|
|
buttonView.backgroundColor = .Signal.ColorBase.button
|
|
buttonView.textColor = .Signal.ColorBase.labelPrimary
|
|
}
|
|
subviews.append(buttonView)
|
|
componentView.buttonViews.append(buttonView)
|
|
}
|
|
|
|
let stackView = componentView.stackView
|
|
stackView.reset()
|
|
stackView.configure(
|
|
config: stackConfig,
|
|
cellMeasurement: cellMeasurement,
|
|
measurementKey: Self.measurementKey_stackView,
|
|
subviews: subviews,
|
|
)
|
|
}
|
|
|
|
private var stackConfig: CVStackViewConfig {
|
|
CVStackViewConfig(
|
|
axis: .vertical,
|
|
alignment: .fill,
|
|
spacing: Self.buttonSpacing,
|
|
layoutMargins: .init(top: 6, leading: 12, bottom: 12, trailing: 12),
|
|
)
|
|
}
|
|
|
|
fileprivate static var buttonHeight: CGFloat { CVMessageActionButton.buttonHeight }
|
|
fileprivate static let buttonSpacing: CGFloat = 4
|
|
|
|
private static let measurementKey_stackView = "CVComponentBottomButtons.measurementKey_stackView"
|
|
|
|
public func measure(maxWidth: CGFloat, measurementBuilder: CVCellMeasurement.Builder) -> CGSize {
|
|
owsAssertDebug(maxWidth > 0)
|
|
|
|
let subviewSize = CGSize(width: maxWidth - stackConfig.layoutMargins.totalWidth, height: Self.buttonHeight)
|
|
var subviewInfos = [ManualStackSubviewInfo]()
|
|
for _ in 0..<actions.count {
|
|
subviewInfos.append(subviewSize.asManualSubviewInfo)
|
|
}
|
|
let stackMeasurement = ManualStackView.measure(
|
|
config: stackConfig,
|
|
measurementBuilder: measurementBuilder,
|
|
measurementKey: Self.measurementKey_stackView,
|
|
subviewInfos: subviewInfos,
|
|
maxWidth: maxWidth,
|
|
)
|
|
return stackMeasurement.measuredSize
|
|
}
|
|
|
|
// MARK: - Events
|
|
|
|
override public func handleTap(
|
|
sender: UIGestureRecognizer,
|
|
componentDelegate: CVComponentDelegate,
|
|
componentView: CVComponentView,
|
|
renderItem: CVRenderItem,
|
|
) -> Bool {
|
|
|
|
guard let componentView = componentView as? CVComponentViewBottomButtons else {
|
|
owsFailDebug("Unexpected componentView.")
|
|
return false
|
|
}
|
|
|
|
for buttonView in componentView.buttonViews {
|
|
let location = sender.location(in: buttonView)
|
|
guard buttonView.bounds.contains(location) else {
|
|
continue
|
|
}
|
|
buttonView.action.perform(delegate: componentDelegate)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
private class CVMessageActionButton: CVLabel {
|
|
|
|
let action: CVMessageAction
|
|
|
|
init(action: CVMessageAction) {
|
|
self.action = action
|
|
|
|
super.init(frame: .zero)
|
|
|
|
configure()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
private func configure() {
|
|
layoutMargins = .zero
|
|
layer.masksToBounds = true
|
|
layer.cornerRadius = Self.buttonHeight / 2
|
|
text = action.title
|
|
font = Self.buttonFont
|
|
textAlignment = .center
|
|
}
|
|
|
|
private static var buttonFont: UIFont { UIFont.dynamicTypeFootnoteClamped.medium() }
|
|
|
|
private static let buttonVMargin: CGFloat = 5
|
|
|
|
static var buttonHeight: CGFloat {
|
|
ceil(buttonFont.lineHeight + buttonVMargin * 2).clamp(28, 44)
|
|
}
|
|
}
|
|
|
|
private class CVComponentViewBottomButtons: NSObject, CVComponentView {
|
|
|
|
let stackView = ManualStackView(name: "bottomButtons")
|
|
var buttonViews = [CVMessageActionButton]()
|
|
|
|
var isDedicatedCellView = false
|
|
|
|
var rootView: UIView {
|
|
stackView
|
|
}
|
|
|
|
func setIsCellVisible(_ isCellVisible: Bool) {}
|
|
|
|
func reset() {
|
|
stackView.reset()
|
|
|
|
buttonViews.removeAll()
|
|
}
|
|
}
|
|
}
|