From 6bb7e4473bc919dc61e940f546cdabdd7b2e4089 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 7 Oct 2019 17:00:13 -0300 Subject: [PATCH] Render blur hashes in conversation view. --- .../Cells/ConversationMediaView.swift | 54 +++++++++++++++++++ .../src/Messages/Attachments/BlurHash.swift | 19 +++++++ 2 files changed, 73 insertions(+) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift index ac70c86952..446f45a388 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift @@ -121,6 +121,7 @@ public class ConversationMediaView: UIView { AssertIsOnMainThread() guard let attachmentStream = attachment as? TSAttachmentStream else { + tryToConfigureForBlurHash(attachment: attachment) addDownloadProgressIfNecessary() return } @@ -185,6 +186,59 @@ public class ConversationMediaView: UIView { return true } + private func tryToConfigureForBlurHash(attachment: TSAttachment) { + guard let pointer = attachment as? TSAttachmentPointer else { + owsFailDebug("Invalid attachment.") + return + } + guard let blurHash = pointer.blurHash, + blurHash.count > 0 else { + return + } + let cacheKey = blurHash + let stillImageView = UIImageView() + // We need to specify a contentMode since the size of the image + // might not match the aspect ratio of the view. + stillImageView.contentMode = .scaleAspectFill + // Use trilinear filters for better scaling quality at + // some performance cost. + stillImageView.layer.minificationFilter = .trilinear + stillImageView.layer.magnificationFilter = .trilinear + stillImageView.backgroundColor = Theme.washColor + addSubview(stillImageView) + stillImageView.autoPinEdgesToSuperviewEdges() + loadBlock = { [weak self] in + AssertIsOnMainThread() + + if stillImageView.image != nil { + owsFailDebug("Unexpectedly already loaded.") + return + } + self?.tryToLoadMedia(loadMediaBlock: { () -> AnyObject? in + guard let image = BlurHash.image(for: blurHash) else { + Logger.warn("Missing image for blurHash.") + return nil + } + return image + }, + applyMediaBlock: { (media) in + AssertIsOnMainThread() + + guard let image = media as? UIImage else { + owsFailDebug("Media has unexpected type: \(type(of: media))") + return + } + stillImageView.image = image + }, + cacheKey: cacheKey) + } + unloadBlock = { + AssertIsOnMainThread() + + stillImageView.image = nil + } + } + private func configureForAnimatedImage(attachmentStream: TSAttachmentStream) { let cacheKey = attachmentStream.uniqueId let animatedImageView = YYAnimatedImageView() diff --git a/SignalServiceKit/src/Messages/Attachments/BlurHash.swift b/SignalServiceKit/src/Messages/Attachments/BlurHash.swift index ca6932f0e0..0b42fc8c16 100644 --- a/SignalServiceKit/src/Messages/Attachments/BlurHash.swift +++ b/SignalServiceKit/src/Messages/Attachments/BlurHash.swift @@ -84,4 +84,23 @@ public class BlurHash: NSObject { return promise } + + @objc(imageForBlurHash:) + public class func image(for blurHash: String) -> UIImage? { + // A small thumbnail size will suffice. + // + // We use a slightly smaller size than we need to + // to future-proof this in case we decide to improve + // the quality in a future release. + // + // We could extract the content size from the + // blurHash, but it doesn't seem worth the trouble. + let thumbnailDimension: CGFloat = 16 + let thumbnailSize = CGSize(width: thumbnailDimension, height: thumbnailDimension) + guard let image = UIImage(blurHash: blurHash, size: thumbnailSize) else { + owsFailDebug("Couldn't generate image for blurHash.") + return nil + } + return image + } }