diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.h b/Riot/Modules/Room/CellData/RoomBubbleCellData.h index f4f7e8078..1e55e8446 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.h +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.h @@ -82,10 +82,15 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) @property(nonatomic, readonly) CGFloat additionalContentHeight; /** - A link if the textMessage contains one, otherwise nil. + The data necessary to show a URL preview. */ @property (nonatomic) URLPreviewData *urlPreviewData; +/** + Whether a URL preview should be displayed for this cell. + */ +@property (nonatomic) BOOL showURLPreview; + /** MXKeyVerification object associated to key verification event when using key verification by direct message. */ diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index 5ddb7c4e8..0ef615ad1 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -1070,8 +1070,9 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat return; } - // Check that the preview hasn't been dismissed already. - if ([URLPreviewManager.shared hasClosedPreviewFrom:lastComponent.event]) + // Don't show the preview if it has been dismissed already. + self.showURLPreview = ![URLPreviewManager.shared hasClosedPreviewFrom:lastComponent.event]; + if (!self.showURLPreview) { return; } diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index b379830c9..c4fce1cdd 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -388,8 +388,8 @@ const CGFloat kTypingCellHeight = 24; NSURL *link = component.link; URLPreviewView *urlPreviewView; - // Encrypted rooms must not show URL previews. - if (link && cellData.urlPreviewData && !self.room.summary.isEncrypted) + // Show a URL preview if the component has a link that should be previewed. + if (link && cellData.showURLPreview) { urlPreviewView = [URLPreviewView instantiate]; urlPreviewView.preview = cellData.urlPreviewData; @@ -1261,7 +1261,8 @@ const CGFloat kTypingCellHeight = 24; // Remember that the user closed the preview so it isn't shown again. [URLPreviewManager.shared closePreviewFor:eventID in:roomID]; - // Remove the preview data and refresh the cells. + // Hide the preview, remove its data and refresh the cells. + cellData.showURLPreview = NO; cellData.urlPreviewData = nil; [self refreshCells]; } diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgBubbleCell.m index e7bb2fbce..cb6bef798 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgBubbleCell.m +++ b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgBubbleCell.m @@ -43,7 +43,7 @@ { RoomBubbleCellData *bubbleData = (RoomBubbleCellData*)cellData; - if (bubbleData && bubbleData.urlPreviewData) + if (bubbleData && bubbleData.showURLPreview) { CGFloat height = [super heightForCellData:cellData withMaximumWidth:maxWidth]; return height + RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:bubbleData.urlPreviewData]; diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m index 3d88949e4..a1cf37c78 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m +++ b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m @@ -49,7 +49,7 @@ { RoomBubbleCellData *bubbleData = (RoomBubbleCellData*)cellData; - if (bubbleData && bubbleData.urlPreviewData) + if (bubbleData && bubbleData.showURLPreview) { CGFloat height = [super heightForCellData:cellData withMaximumWidth:maxWidth]; return height + RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:bubbleData.urlPreviewData]; diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m index 3b8c32635..219c18f77 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/Views/BubbleCells/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m @@ -33,7 +33,7 @@ { RoomBubbleCellData *bubbleData = (RoomBubbleCellData*)cellData; - if (bubbleData && bubbleData.urlPreviewData) + if (bubbleData && bubbleData.showURLPreview) { CGFloat height = [super heightForCellData:cellData withMaximumWidth:maxWidth]; return height + RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:bubbleData.urlPreviewData]; diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgBubbleCell.m index 9a1a6efa4..55210fcd5 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgBubbleCell.m +++ b/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgBubbleCell.m @@ -44,7 +44,7 @@ { RoomBubbleCellData *bubbleData = (RoomBubbleCellData*)cellData; - if (bubbleData && bubbleData.urlPreviewData) + if (bubbleData && bubbleData.showURLPreview) { CGFloat height = [super heightForCellData:cellData withMaximumWidth:maxWidth]; return height + RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:bubbleData.urlPreviewData]; diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m index 82b54239c..b8de02021 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/Views/BubbleCells/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m @@ -33,7 +33,7 @@ { RoomBubbleCellData *bubbleData = (RoomBubbleCellData*)cellData; - if (bubbleData && bubbleData.urlPreviewData) + if (bubbleData && bubbleData.showURLPreview) { CGFloat height = [super heightForCellData:cellData withMaximumWidth:maxWidth]; return height + RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:bubbleData.urlPreviewData]; diff --git a/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.swift b/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.swift index f627b0062..a34b06e67 100644 --- a/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.swift +++ b/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.swift @@ -37,7 +37,10 @@ class URLPreviewView: UIView, NibLoadable, Themable { var preview: URLPreviewData? { didSet { - guard let preview = preview else { return } + guard let preview = preview else { + renderLoading() + return + } renderLoaded(preview) } } @@ -47,10 +50,15 @@ class URLPreviewView: UIView, NibLoadable, Themable { @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var closeButton: UIButton! + @IBOutlet weak var textContainerView: UIView! @IBOutlet weak var siteNameLabel: UILabel! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var descriptionLabel: UILabel! + @IBOutlet weak var loadingView: UIView! + @IBOutlet weak var loadingLabel: UILabel! + @IBOutlet weak var loadingActivityIndicator: UIActivityIndicatorView! + // Matches the label's height with the close button. // Use a strong reference to keep it around when deactivating. @IBOutlet var siteNameLabelHeightConstraint: NSLayoutConstraint! @@ -98,14 +106,21 @@ class URLPreviewView: UIView, NibLoadable, Themable { descriptionLabel.textColor = theme.colors.secondaryContent descriptionLabel.font = theme.fonts.caption1 + loadingLabel.textColor = siteNameLabel.textColor + let closeButtonAsset = ThemeService.shared().isCurrentThemeDark() ? Asset.Images.urlPreviewCloseDark : Asset.Images.urlPreviewClose closeButton.setImage(closeButtonAsset.image, for: .normal) } - static func contentViewHeight(for preview: URLPreviewData) -> CGFloat { + static func contentViewHeight(for preview: URLPreviewData?) -> CGFloat { sizingView.frame = CGRect(x: 0, y: 0, width: Constants.width, height: 1) - sizingView.renderLoaded(preview) + // Call render directly to avoid storing the preview data in the sizing view + if let preview = preview { + sizingView.renderLoaded(preview) + } else { + sizingView.renderLoading() + } sizingView.setNeedsLayout() sizingView.layoutIfNeeded() @@ -117,16 +132,18 @@ class URLPreviewView: UIView, NibLoadable, Themable { } // MARK: - Private - #warning("Check whether we should show a loading state.") - private func renderLoading(_ url: URL) { - imageView.image = nil + private func renderLoading() { + // hide the content + imageView.isHidden = true + textContainerView.isHidden = true - siteNameLabel.text = url.host - titleLabel.text = "Loading..." - descriptionLabel.text = "" + // show the loading interface + loadingView.isHidden = false + loadingActivityIndicator.startAnimating() } private func renderLoaded(_ preview: URLPreviewData) { + // update preview content imageView.image = preview.image siteNameLabel.text = preview.siteName ?? preview.url.host titleLabel.text = preview.title @@ -136,6 +153,13 @@ class URLPreviewView: UIView, NibLoadable, Themable { } private func updateLayout() { + // hide the loading interface + loadingView.isHidden = true + loadingActivityIndicator.stopAnimating() + + // show the content + textContainerView.isHidden = false + if imageView.image == nil { imageView.isHidden = true diff --git a/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.xib b/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.xib index 05b19e57b..1675f2a6d 100644 --- a/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.xib +++ b/Riot/Modules/Room/Views/URLPreviews/URLPreviewView.xib @@ -10,11 +10,11 @@ - + - + @@ -22,11 +22,11 @@ - - + + - + - - - - @@ -64,6 +60,31 @@ + + + + + + + + + + + + + + + + + @@ -92,12 +113,16 @@ + + + + - +