From 3a98384275a1eccc9faef8703f49ef65cc044a92 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 1 Feb 2021 15:13:10 -0300 Subject: [PATCH] Do not linkify message bodies if there is a pending message request. --- .../CV/CVComponentState.swift | 24 ++++++++--------- .../CV/CVComponents/CVComponentBodyText.swift | 26 ++++++++++++++++--- .../ConversationView/CV/CVItemViewState.swift | 7 ++++- .../ConversationView/CV/CVLoader.swift | 1 + 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVComponentState.swift b/Signal/src/ViewControllers/ConversationView/CV/CVComponentState.swift index 27ae8c506c..e8dffff626 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVComponentState.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVComponentState.swift @@ -971,34 +971,34 @@ fileprivate extension CVComponentState.Builder { owsFailDebug("Invalid attachment.") } mediaAlbumItems.append(CVMediaAlbumItem(attachment: attachment, - attachmentStream: nil, - caption: caption, - mediaSize: mediaSize)) + attachmentStream: nil, + caption: caption, + mediaSize: mediaSize)) continue } guard attachmentStream.isValidVisualMedia else { Logger.warn("Filtering invalid media.") mediaAlbumItems.append(CVMediaAlbumItem(attachment: attachment, - attachmentStream: nil, - caption: caption, - mediaSize: .zero)) + attachmentStream: nil, + caption: caption, + mediaSize: .zero)) continue } let mediaSize = attachmentStream.imageSize() if mediaSize.width <= 0 || mediaSize.height <= 0 { Logger.warn("Filtering media with invalid size.") mediaAlbumItems.append(CVMediaAlbumItem(attachment: attachment, - attachmentStream: nil, - caption: caption, - mediaSize: .zero)) + attachmentStream: nil, + caption: caption, + mediaSize: .zero)) continue } mediaAlbumItems.append(CVMediaAlbumItem(attachment: attachment, - attachmentStream: attachmentStream, - caption: caption, - mediaSize: mediaSize)) + attachmentStream: attachmentStream, + caption: caption, + mediaSize: mediaSize)) } return mediaAlbumItems } diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentBodyText.swift b/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentBodyText.swift index 5af72504b8..7b49000790 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentBodyText.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentBodyText.swift @@ -13,6 +13,7 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { let searchText: String? let hasTapForMore: Bool let shouldUseAttributedText: Bool + let hasPendingMessageRequest: Bool public var canUseDedicatedCell: Bool { if hasTapForMore || searchText != nil { @@ -49,6 +50,9 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { private var hasTapForMore: Bool { bodyTextState.hasTapForMore } + private var hasPendingMessageRequest: Bool { + bodyTextState.hasPendingMessageRequest + } public var shouldUseAttributedText: Bool { bodyTextState.shouldUseAttributedText } @@ -104,10 +108,15 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { private static let unfairLock = UnfairLock() private static func shouldUseAttributedText(text: String, + hasPendingMessageRequest: Bool, shouldAllowLinkification: Bool) -> Bool { // Use a lock to ensure that measurement on and off the main thread // don't conflict. unfairLock.withLock { + guard !hasPendingMessageRequest else { + // Do not linkify if there is a pending message request. + return false + } // NSDataDetector and UIDataDetector behavior should be aligned. // // TODO: We might want to move this detection logic into @@ -117,14 +126,16 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { owsFailDebug("Could not build dataDetector.") return true } - return !detector.matches(in: text, options: [], range: text.entireRange).isEmpty + let hasLinks = !detector.matches(in: text, options: [], range: text.entireRange).isEmpty + return hasLinks } } static func buildState(interaction: TSInteraction, bodyText: CVComponentState.BodyText, viewStateSnapshot: CVViewStateSnapshot, - hasTapForMore: Bool) -> State { + hasTapForMore: Bool, + hasPendingMessageRequest: Bool) -> State { let textExpansion = viewStateSnapshot.textExpansion let searchText = viewStateSnapshot.searchText let isTextExpanded = textExpansion.isTextExpanded(interactionId: interaction.uniqueId) @@ -147,6 +158,7 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { } else { let shouldAllowLinkification = displayableText.shouldAllowLinkification shouldUseAttributedText = self.shouldUseAttributedText(text: text, + hasPendingMessageRequest: hasPendingMessageRequest, shouldAllowLinkification: shouldAllowLinkification) } case .attributedText: @@ -158,7 +170,8 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { isTextExpanded: isTextExpanded, searchText: searchText, hasTapForMore: hasTapForMore, - shouldUseAttributedText: shouldUseAttributedText) + shouldUseAttributedText: shouldUseAttributedText, + hasPendingMessageRequest: hasPendingMessageRequest) } static func buildComponentState(message: TSMessage, @@ -303,7 +316,12 @@ public class CVComponentBodyText: CVComponentBase, CVComponent { } textView.shouldIgnoreEvents = shouldIgnoreEvents - textView.ensureShouldLinkifyText(displayableText.shouldAllowLinkification) + if hasPendingMessageRequest { + // Do not linkify test if there is a pending message request for this conversation. + textView.dataDetectorTypes = [] + } else { + textView.ensureShouldLinkifyText(displayableText.shouldAllowLinkification) + } textViewConfig.applyForRendering(textView: textView) diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVItemViewState.swift b/Signal/src/ViewControllers/ConversationView/CV/CVItemViewState.swift index ef1fb50704..4b6b3fb55b 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVItemViewState.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVItemViewState.swift @@ -159,6 +159,7 @@ struct CVItemModelBuilder: CVItemBuilding { previousItem: previousItem, nextItem: nextItem, thread: thread, + threadViewModel: threadViewModel, viewStateSnapshot: viewStateSnapshot, transaction: transaction) } @@ -170,6 +171,7 @@ struct CVItemModelBuilder: CVItemBuilding { public static func buildStandaloneItem(interaction: TSInteraction, thread: TSThread, + threadViewModel: ThreadViewModel, itemBuildingContext: CVItemBuildingContext, transaction: SDSAnyReadTransaction) -> CVItemModel? { AssertIsOnMainThread() @@ -188,6 +190,7 @@ struct CVItemModelBuilder: CVItemBuilding { previousItem: nil, nextItem: nil, thread: thread, + threadViewModel: threadViewModel, viewStateSnapshot: viewStateSnapshot, transaction: transaction) @@ -198,6 +201,7 @@ struct CVItemModelBuilder: CVItemBuilding { previousItem: ItemBuilder?, nextItem: ItemBuilder?, thread: TSThread, + threadViewModel: ThreadViewModel, viewStateSnapshot: CVViewStateSnapshot, transaction: SDSAnyReadTransaction) { let itemViewState = item.itemViewState @@ -231,7 +235,8 @@ struct CVItemModelBuilder: CVItemBuilding { itemViewState.bodyTextState = CVComponentBodyText.buildState(interaction: interaction, bodyText: bodyText, viewStateSnapshot: viewStateSnapshot, - hasTapForMore: hasTapForMore) + hasTapForMore: hasTapForMore, + hasPendingMessageRequest: threadViewModel.hasPendingMessageRequest) } itemViewState.isShowingSelectionUI = viewStateSnapshot.isShowingSelectionUI diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVLoader.swift b/Signal/src/ViewControllers/ConversationView/CV/CVLoader.swift index 374ae9b975..6b8594c229 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVLoader.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVLoader.swift @@ -291,6 +291,7 @@ public class CVLoader: NSObject { avatarBuilder: avatarBuilder) guard let itemModel = CVItemModelBuilder.buildStandaloneItem(interaction: interaction, thread: thread, + threadViewModel: threadViewModel, itemBuildingContext: itemBuildingContext, transaction: transaction) else { owsFailDebug("Couldn't build item model.")