diff --git a/Session/Conversations V2/ConversationVC.swift b/Session/Conversations V2/ConversationVC.swift index 0a90f8c55..c26499b7d 100644 --- a/Session/Conversations V2/ConversationVC.swift +++ b/Session/Conversations V2/ConversationVC.swift @@ -7,13 +7,16 @@ // • Photo rounding // • Disappearing messages timer // • Scroll button behind mentions view -// • Remaining search bugs +// • Remaining search glitchiness +// • Brendan no likey buttons above text field final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversationSettingsViewDelegate, ConversationSearchControllerDelegate, UITableViewDataSource, UITableViewDelegate { let thread: TSThread let focusedMessageID: String? var didConstrainScrollButton = false + // Search var isShowingSearchUI = false + var lastSearchedText: String? // Audio playback & recording var audioPlayer: OWSAudioPlayer? var audioRecorder: AVAudioRecorder? @@ -60,6 +63,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat lazy var searchController: ConversationSearchController = { let result = ConversationSearchController(thread: thread) result.delegate = self + if #available(iOS 13, *) { + result.uiSearchController.obscuresBackgroundDuringPresentation = false + } else { + result.uiSearchController.dimsBackgroundDuringPresentation = false + } return result }() @@ -469,6 +477,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat let navBar = navigationController!.navigationBar as! OWSNavigationBar navBar.stubbedNextResponder = nil becomeFirstResponder() + reloadInputViews() } func didDismissSearchController(_ searchController: UISearchController) { @@ -476,6 +485,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat } func conversationSearchController(_ conversationSearchController: ConversationSearchController, didUpdateSearchResults resultSet: ConversationScreenSearchResultSet?) { + lastSearchedText = resultSet?.searchText messagesTableView.reloadRows(at: messagesTableView.indexPathsForVisibleRows ?? [], with: UITableView.RowAnimation.none) } diff --git a/Session/Conversations V2/Input View/InputView.swift b/Session/Conversations V2/Input View/InputView.swift index 26b483eca..f663b6b07 100644 --- a/Session/Conversations V2/Input View/InputView.swift +++ b/Session/Conversations V2/Input View/InputView.swift @@ -17,6 +17,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, } override var intrinsicContentSize: CGSize { CGSize.zero } + var lastSearchedText: String? { nil } // MARK: UI Components private lazy var cameraButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self) diff --git a/Session/Conversations V2/Message Cells/Content Views/LinkPreviewViewV2.swift b/Session/Conversations V2/Message Cells/Content Views/LinkPreviewViewV2.swift index 1980e6aac..983ea42fa 100644 --- a/Session/Conversations V2/Message Cells/Content Views/LinkPreviewViewV2.swift +++ b/Session/Conversations V2/Message Cells/Content Views/LinkPreviewViewV2.swift @@ -151,7 +151,7 @@ final class LinkPreviewViewV2 : UIView { // Body text view bodyTextViewContainer.subviews.forEach { $0.removeFromSuperview() } if let viewItem = viewItem { - let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: sentLinkPreviewTextColor, delegate: delegate) + let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: sentLinkPreviewTextColor, searchText: delegate.lastSearchedText, delegate: delegate) bodyTextViewContainer.addSubview(bodyTextView) bodyTextView.pin(to: bodyTextViewContainer, withInset: 12) } @@ -168,6 +168,7 @@ final class LinkPreviewViewV2 : UIView { // MARK: Delegate protocol LinkPreviewViewV2Delegate : UITextViewDelegate & BodyTextViewDelegate { + var lastSearchedText: String? { get } func handleLinkPreviewCanceled() } diff --git a/Session/Conversations V2/Message Cells/MessageCell.swift b/Session/Conversations V2/Message Cells/MessageCell.swift index a3f700f64..c4d760087 100644 --- a/Session/Conversations V2/Message Cells/MessageCell.swift +++ b/Session/Conversations V2/Message Cells/MessageCell.swift @@ -50,6 +50,7 @@ class MessageCell : UITableViewCell { } protocol MessageCellDelegate { + var lastSearchedText: String? { get } func getMediaCache() -> NSCache func handleViewItemLongPressed(_ viewItem: ConversationViewItem) diff --git a/Session/Conversations V2/Message Cells/VisibleMessageCell.swift b/Session/Conversations V2/Message Cells/VisibleMessageCell.swift index 33495d2d3..ea2a90d0a 100644 --- a/Session/Conversations V2/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations V2/Message Cells/VisibleMessageCell.swift @@ -25,6 +25,8 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewV2Delegate { return result }() + var lastSearchedText: String? { delegate?.lastSearchedText } + private var positionInCluster: Position? { guard let viewItem = viewItem else { return nil } if viewItem.isFirstInCluster { return .top } @@ -290,7 +292,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewV2Delegate { stackView.addArrangedSubview(quoteViewContainer) } // Body text view - let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: bodyLabelTextColor, delegate: self) + let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: bodyLabelTextColor, searchText: delegate?.lastSearchedText, delegate: self) self.bodyTextView = bodyTextView stackView.addArrangedSubview(bodyTextView) // Constraints @@ -531,7 +533,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewV2Delegate { return isGroupThread && viewItem.shouldShowSenderProfilePicture && senderSessionID != nil } - static func getBodyTextView(for viewItem: ConversationViewItem, with availableWidth: CGFloat, textColor: UIColor, delegate: UITextViewDelegate & BodyTextViewDelegate) -> UITextView { + static func getBodyTextView(for viewItem: ConversationViewItem, with availableWidth: CGFloat, textColor: UIColor, searchText: String?, delegate: UITextViewDelegate & BodyTextViewDelegate) -> UITextView { guard let message = viewItem.interaction as? TSMessage else { preconditionFailure() } let isOutgoing = (message.interactionType() == .outgoingMessage) let result = BodyTextView(snDelegate: delegate) @@ -540,7 +542,23 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewV2Delegate { .foregroundColor : textColor, .font : UIFont.systemFont(ofSize: getFontSize(for: viewItem)) ] - result.attributedText = given(message.body) { MentionUtilities.highlightMentions(in: $0, isOutgoingMessage: isOutgoing, threadID: viewItem.interaction.uniqueThreadId, attributes: attributes) } + var attributedText = NSMutableAttributedString(attributedString: MentionUtilities.highlightMentions(in: message.body ?? "", isOutgoingMessage: isOutgoing, threadID: viewItem.interaction.uniqueThreadId, attributes: attributes)) + + if let searchText = searchText, searchText.count >= ConversationSearchController.kMinimumSearchTextLength { + let normalizedSearchText = FullTextSearchFinder.normalize(text: searchText) + do { + let regex = try NSRegularExpression(pattern: NSRegularExpression.escapedPattern(for: normalizedSearchText), options: .caseInsensitive) + let matches = regex.matches(in: attributedText.string, options: .withoutAnchoringBounds, range: NSRange(location: 0, length: (attributedText.string as NSString).length)) + for match in matches { + guard match.range.location + match.range.length < attributedText.length else { continue } + attributedText.addAttribute(.backgroundColor, value: UIColor.white, range: match.range) + attributedText.addAttribute(.foregroundColor, value: UIColor.black, range: match.range) + } + } catch { + + } + } + result.attributedText = attributedText result.dataDetectorTypes = .link result.backgroundColor = .clear result.isOpaque = false