Make call links icon into UIImage using UIGraphics

This commit is contained in:
Marissa Le Coz 2024-09-26 16:57:38 -04:00 committed by GitHub
parent 1b28fd7ba0
commit a84400a4fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 146 deletions

View File

@ -407,8 +407,14 @@ private class _CreateCallLinkViewController: OWSTableViewController2 {
// MARK: - CallLinkCardView
private class CallLinkCardView: UIView {
private lazy var circleView: UIView = {
return SignalUI.CallLinkComponentFactory.callLinkIconView()
private lazy var iconView: UIImageView = {
let image = CommonCallLinksUI.callLinkIcon()
let imageView = UIImageView(image: image)
imageView.autoSetDimensions(to: CGSize(
width: Constants.circleViewDimension,
height: Constants.circleViewDimension
))
return imageView
}()
private lazy var textStack: UIStackView = {
@ -506,7 +512,7 @@ private class CallLinkCardView: UIView {
super.init(frame: .zero)
let stackView = UIStackView()
stackView.addArrangedSubviews([circleView, textStack, joinButton])
stackView.addArrangedSubviews([iconView, textStack, joinButton])
stackView.axis = .horizontal
stackView.distribution = .fillProportionally
stackView.alignment = .center
@ -525,5 +531,45 @@ private class CallLinkCardView: UIView {
static let spacingTextToButton: CGFloat = 16
static let spacingIconToText: CGFloat = 12
static let textStackSpacing: CGFloat = 2
static let circleViewDimension: CGFloat = CommonCallLinksUI.Constants.circleViewDimension
}
}
public class CommonCallLinksUI {
public static func callLinkIcon() -> UIImage? {
guard let image = UIImage(named: "video-compact") else { return nil }
let newSize = CGSize(square: Constants.circleViewDimension)
let renderer = UIGraphicsImageRenderer(size: newSize)
let finalImage = renderer.image { context in
let rect = CGRect(origin: .zero, size: newSize)
let circlePath = UIBezierPath(ovalIn: rect)
Constants.iconBackgroundColor.setFill()
circlePath.fill()
context.cgContext.addPath(circlePath.cgPath)
context.cgContext.clip()
Constants.iconTintColor.set()
let centerOffset = Constants.circleViewDimension/2 - Constants.iconDimension/2
let imageRect = CGRect(
x: centerOffset,
y: centerOffset,
width: Constants.iconDimension,
height: Constants.iconDimension
)
image.withRenderingMode(.alwaysTemplate).draw(in: imageRect)
}
return finalImage
}
enum Constants {
static let circleViewDimension: CGFloat = 64
fileprivate static let iconDimension: CGFloat = 36
fileprivate static let iconBackgroundColor = UIColor(rgbHex: 0xE4E4FD)
fileprivate static let iconTintColor = UIColor(rgbHex: 0x5151F6)
}
}

View File

@ -48,13 +48,16 @@ class LinkPreviewCallLink: LinkPreviewState {
return .loaded
}
public func imageAsync(thumbnailQuality: AttachmentThumbnailQuality, completion: @escaping (UIImage) -> Void) {}
public func imageAsync(thumbnailQuality: AttachmentThumbnailQuality, completion: @escaping (UIImage) -> Void) {
if let image = CommonCallLinksUI.callLinkIcon() {
completion(image)
}
}
public func imageCacheKey(thumbnailQuality: AttachmentThumbnailQuality) -> LinkPreviewImageCacheKey? { return nil }
public var imagePixelSize: CGSize {
// This value does not matter since the image is local for call links.
return .zero
return CGSize(square: CommonCallLinksUI.Constants.circleViewDimension)
}
public var previewDescription: String? {

View File

@ -336,7 +336,7 @@ public class LinkPreviewSent: LinkPreviewState {
public var date: Date? { linkPreview.date }
public let isGroupInviteLink = false
public var isCallLink = false
public let isCallLink = false
public var activityIndicatorStyle: UIActivityIndicatorView.Style {
LinkPreviewView.defaultActivityIndicatorStyle

View File

@ -139,8 +139,6 @@ public class LinkPreviewView: ManualStackViewWithLayer {
return LinkPreviewViewAdapterDraft(state: state)
} else if state.isGroupInviteLink {
return LinkPreviewViewAdapterGroupLink(state: state)
} else if state.isCallLink {
return LinkPreviewViewAdapterCallLink(state: state)
} else {
if state.hasLoadedImage {
if Self.sentIsHero(state: state) {
@ -914,143 +912,6 @@ private class LinkPreviewViewAdapterGroupLink: LinkPreviewViewAdapter {
// MARK: -
private class LinkPreviewViewAdapterCallLink: LinkPreviewViewAdapter {
let state: LinkPreviewState
init(state: LinkPreviewState) {
self.state = state
}
var rootStackConfig: ManualStackView.Config {
ManualStackView.Config(
axis: .horizontal,
alignment: .fill,
spacing: LinkPreviewView.sentNonHeroHSpacing,
layoutMargins: LinkPreviewView.sentNonHeroLayoutMargins
)
}
var textStackConfig: ManualStackView.Config {
return ManualStackView.Config(
axis: .vertical,
alignment: .leading,
spacing: LinkPreviewView.sentVSpacing,
layoutMargins: .zero
)
}
func configureForRendering(
linkPreviewView: LinkPreviewView,
hasAsymmetricalRounding: Bool,
cellMeasurement: CVCellMeasurement
) {
linkPreviewView.backgroundColor = Theme.secondaryBackgroundColor
var rootStackSubviews = [UIView]()
let iconView = CallLinkComponentFactory.callLinkIconView()
iconView.contentMode = .scaleAspectFill
iconView.clipsToBounds = true
rootStackSubviews.append(iconView)
let textStack = linkPreviewView.textStack
var textStackSubviews = [UIView]()
if let titleLabel = sentTitleLabel(state: state) {
textStackSubviews.append(titleLabel)
}
if let descriptionLabel = sentDescriptionLabel(state: state) {
textStackSubviews.append(descriptionLabel)
}
textStack.configure(
config: textStackConfig,
cellMeasurement: cellMeasurement,
measurementKey: Self.measurementKey_textStack,
subviews: textStackSubviews
)
rootStackSubviews.append(textStack)
linkPreviewView.configure(
config: rootStackConfig,
cellMeasurement: cellMeasurement,
measurementKey: Self.measurementKey_rootStack,
subviews: rootStackSubviews
)
}
func measure(
maxWidth: CGFloat,
measurementBuilder: CVCellMeasurement.Builder,
state: LinkPreviewState
) -> CGSize {
var maxLabelWidth = (maxWidth - (
textStackConfig.layoutMargins.totalWidth + rootStackConfig.layoutMargins.totalWidth
))
var rootStackSubviewInfos = [ManualStackSubviewInfo]()
let imageSize = LinkPreviewView.sentNonHeroImageSize
rootStackSubviewInfos.append(CGSize.square(imageSize).asManualSubviewInfo(hasFixedSize: true))
maxLabelWidth -= imageSize + rootStackConfig.spacing
maxLabelWidth = max(0, maxLabelWidth)
var textStackSubviewInfos = [ManualStackSubviewInfo]()
if let labelConfig = sentTitleLabelConfig(state: state) {
let labelSize = CVText.measureLabel(config: labelConfig, maxWidth: maxLabelWidth)
textStackSubviewInfos.append(labelSize.asManualSubviewInfo)
}
if let labelConfig = sentDescriptionLabelConfig(state: state) {
let labelSize = CVText.measureLabel(config: labelConfig, maxWidth: maxLabelWidth)
textStackSubviewInfos.append(labelSize.asManualSubviewInfo)
}
let textStackMeasurement = ManualStackView.measure(
config: textStackConfig,
measurementBuilder: measurementBuilder,
measurementKey: Self.measurementKey_textStack,
subviewInfos: textStackSubviewInfos
)
rootStackSubviewInfos.append(textStackMeasurement.measuredSize.asManualSubviewInfo)
let rootStackMeasurement = ManualStackView.measure(
config: rootStackConfig,
measurementBuilder: measurementBuilder,
measurementKey: Self.measurementKey_rootStack,
subviewInfos: rootStackSubviewInfos,
maxWidth: maxWidth
)
return rootStackMeasurement.measuredSize
}
}
public class CallLinkComponentFactory {
public static func callLinkIconView() -> UIView {
let circleView = CircleView()
circleView.backgroundColor = UIColor(rgbHex: Constants.iconBackgroundColor)
circleView.autoSetDimensions(to: CGSize(width: Constants.circleViewDimension, height: Constants.circleViewDimension))
let iconImageView = UIImageView(image: UIImage(named: "video-compact"))
iconImageView.tintColor = UIColor(rgbHex: Constants.iconTintColor)
iconImageView.autoSetDimensions(to: CGSize(width: Constants.iconDimension, height: Constants.iconDimension))
circleView.addSubview(iconImageView)
iconImageView.autoCenterInSuperview()
return circleView
}
private enum Constants {
static let circleViewDimension: CGFloat = 64
static let iconDimension: CGFloat = 36
static let iconBackgroundColor: UInt32 = 0xE4E4FD
static let iconTintColor: UInt32 = 0x5151F6
}
}
// MARK: -
private class LinkPreviewViewAdapterSentHero: LinkPreviewViewAdapter {
let state: LinkPreviewState