diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index ac4265c58..a7775a9da 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -29,6 +29,7 @@ #import "OWSMessageCell.h" #import "OWSNavigationController.h" #import "OWSProgressView.h" +#import "OWSQuotedMessageView.h" #import "OWSWebRTCDataProtos.pb.h" #import "PinEntryView.h" #import "PrivacySettingsTableViewController.h" diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m index 2b6dd8ec0..cdfc5437c 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m @@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable, readonly) DisplayableText *displayableQuotedText; @property (nonatomic, nullable) OWSBubbleStrokeView *boundsStrokeView; +@property (nonatomic, readonly) BOOL isForPreview; @end @@ -35,8 +36,9 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(quotedMessage); - return - [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage displayableQuotedText:displayableQuotedText]; + return [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage + displayableQuotedText:displayableQuotedText + isForPreview:NO]; } + (OWSQuotedMessageView *)quotedMessageViewForPreview:(OWSQuotedReplyModel *)quotedMessage @@ -48,12 +50,14 @@ NS_ASSUME_NONNULL_BEGIN displayableQuotedText = [DisplayableText displayableText:quotedMessage.body]; } - return - [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage displayableQuotedText:displayableQuotedText]; + return [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage + displayableQuotedText:displayableQuotedText + isForPreview:YES]; } - (instancetype)initWithQuotedMessage:(OWSQuotedReplyModel *)quotedMessage displayableQuotedText:(nullable DisplayableText *)displayableQuotedText + isForPreview:(BOOL)isForPreview { self = [super init]; @@ -65,6 +69,9 @@ NS_ASSUME_NONNULL_BEGIN _quotedMessage = quotedMessage; _displayableQuotedText = displayableQuotedText; + _isForPreview = isForPreview; + + [self createContents]; return self; } @@ -258,7 +265,7 @@ NS_ASSUME_NONNULL_BEGIN } UILabel *quotedTextLabel = [UILabel new]; - quotedTextLabel.numberOfLines = 3; + quotedTextLabel.numberOfLines = self.isForPreview ? 1 : 3; quotedTextLabel.lineBreakMode = NSLineBreakByWordWrapping; quotedTextLabel.text = text; quotedTextLabel.textColor = textColor; diff --git a/Signal/src/views/QuotedReplyPreview.swift b/Signal/src/views/QuotedReplyPreview.swift index dbe9ee0fe..dcb6dc3e9 100644 --- a/Signal/src/views/QuotedReplyPreview.swift +++ b/Signal/src/views/QuotedReplyPreview.swift @@ -13,108 +13,71 @@ protocol QuotedReplyPreviewDelegate: class { class QuotedReplyPreview: UIView { public weak var delegate: QuotedReplyPreviewDelegate? + private let quotedReply: OWSQuotedReplyModel + private var quotedMessageView: OWSQuotedMessageView + private var heightConstraint: NSLayoutConstraint! + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } init(quotedReply: OWSQuotedReplyModel) { + self.quotedReply = quotedReply + self.quotedMessageView = OWSQuotedMessageView(forPreview: quotedReply) + super.init(frame: .zero) - let isQuotingSelf = quotedReply.authorId == TSAccountManager.localNumber() - - // used for stripe and author - // FIXME actual colors TBD - let authorColor: UIColor = isQuotingSelf ? .ows_materialBlue : .black - - // used for text and cancel - let foregroundColor: UIColor = .darkGray - - let authorLabel: UILabel = UILabel() - authorLabel.textColor = authorColor - if isQuotingSelf { - authorLabel.text = NSLocalizedString("MEDIA_GALLERY_SENDER_NAME_YOU", comment: "") - } else { - authorLabel.text = Environment.current().contactsManager.displayName(forPhoneIdentifier: quotedReply.authorId) - } - authorLabel.font = .ows_dynamicTypeHeadline - - let bodyLabel: UILabel = UILabel() - bodyLabel.textColor = foregroundColor - bodyLabel.font = .ows_dynamicTypeFootnote - - bodyLabel.text = { - if let contentType = quotedReply.contentType { - let emoji = TSAttachmentStream.emoji(forMimeType: contentType) - return "\(emoji) \(quotedReply.body ?? "")" - } else { - return quotedReply.body - } - }() - - let thumbnailView: UIView? = { - if let image = quotedReply.thumbnailImage { - let imageView = UIImageView(image: image) - imageView.contentMode = .scaleAspectFill - imageView.autoPinToSquareAspectRatio() - imageView.layer.cornerRadius = 3.0 - imageView.clipsToBounds = true - - return imageView - } - return nil - }() + self.heightConstraint = self.autoSetDimension(.height, toSize: 0) - let cancelButton: UIButton = UIButton(type: .custom) - // FIXME proper image asset/size - let buttonImage: UIImage = #imageLiteral(resourceName: "quoted-message-cancel").withRenderingMode(.alwaysTemplate) - cancelButton.setImage(buttonImage, for: .normal) - cancelButton.imageView?.tintColor = foregroundColor - cancelButton.addTarget(self, action: #selector(didTapCancel), for: .touchUpInside) + updateContents() - let quoteStripe: UIView = UIView() - quoteStripe.backgroundColor = authorColor + NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: .UIContentSizeCategoryDidChange, object: nil) + } - let textColumn = UIView.container() - textColumn.addSubview(authorLabel) - textColumn.addSubview(bodyLabel) + func updateContents() { + subviews.forEach { $0.removeFromSuperview() } + self.quotedMessageView = OWSQuotedMessageView(forPreview: quotedReply) - authorLabel.autoPinEdges(toSuperviewMarginsExcludingEdge: .bottom) - authorLabel.autoPinEdge(.bottom, to: .top, of: bodyLabel) - bodyLabel.autoPinEdges(toSuperviewMarginsExcludingEdge: .top) + quotedMessageView.backgroundColor = .clear - let contentViews: [UIView] = [textColumn, thumbnailView, cancelButton].flatMap { return $0 } - let contentRow = UIStackView(arrangedSubviews: contentViews) - contentRow.axis = .horizontal - self.addSubview(contentRow) - self.addSubview(quoteStripe) + let cancelButton: UIButton = UIButton(type: .custom) - // Layout + let buttonImage: UIImage = #imageLiteral(resourceName: "quoted-message-cancel").withRenderingMode(.alwaysTemplate) + cancelButton.setImage(buttonImage, for: .normal) + cancelButton.imageView?.tintColor = .darkGray + cancelButton.addTarget(self, action: #selector(didTapCancel), for: .touchUpInside) - let kQuoteStripeWidth: CGFloat = 4 - self.layoutMargins = UIEdgeInsets(top: 6, - left: kQuoteStripeWidth + 8, - bottom: 2, - right: 4) + self.layoutMargins = .zero - quoteStripe.autoPinEdge(toSuperviewEdge: .leading) - quoteStripe.autoPinHeightToSuperview() - quoteStripe.autoSetDimension(.width, toSize: kQuoteStripeWidth) + self.addSubview(quotedMessageView) + self.addSubview(cancelButton) - contentRow.autoPinEdgesToSuperviewMargins() + quotedMessageView.autoPinEdges(toSuperviewMarginsExcludingEdge: .trailing) + cancelButton.autoPinEdges(toSuperviewMarginsExcludingEdge: .leading) + cancelButton.autoPinEdge(.leading, to: .trailing, of: quotedMessageView) cancelButton.autoSetDimensions(to: CGSize(width: 40, height: 40)) - } - - // MARK: UIViewOverrides - // Used by stack view to determin size. - override var intrinsicContentSize: CGSize { - return CGSize(width: 0, height: 30) + updateHeight() } // MARK: Actions + @objc func didTapCancel(_ sender: Any) { self.delegate?.quotedReplyPreviewDidPressCancel(self) } + + // MARK: Sizing + + func updateHeight() { + let size = self.quotedMessageView.size(forMaxWidth: CGFloat.infinity) + self.heightConstraint.constant = size.height + } + + func contentSizeCategoryDidChange(_ notification: Notification) { + Logger.debug("\(self.logTag) in \(#function)") + + updateContents() + } }