implement animation for selected search result message flickering

pull/555/head
Ryan Zhao 3 years ago
parent 675dde9b1e
commit c1c5678056

@ -7,7 +7,8 @@
final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversationSettingsViewDelegate, ConversationSearchControllerDelegate, UITableViewDataSource, UITableViewDelegate { final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversationSettingsViewDelegate, ConversationSearchControllerDelegate, UITableViewDataSource, UITableViewDelegate {
let isUnsendRequestsEnabled = true // Set to true once unsend requests are done on all platforms let isUnsendRequestsEnabled = true // Set to true once unsend requests are done on all platforms
let thread: TSThread let thread: TSThread
let focusedMessageID: String? // This isn't actually used ATM let focusedMessageID: String? // This is used for global search
var focusedMessageIndexPath: IndexPath?
var unreadViewItems: [ConversationViewItem] = [] var unreadViewItems: [ConversationViewItem] = []
var scrollButtonConstraint: NSLayoutConstraint? var scrollButtonConstraint: NSLayoutConstraint?
// Search // Search
@ -236,13 +237,17 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
// unreadIndicatorIndex is calculated during loading of the viewItems, so it's // unreadIndicatorIndex is calculated during loading of the viewItems, so it's
// supposed to be accurate. // supposed to be accurate.
DispatchQueue.main.async { DispatchQueue.main.async {
let firstUnreadMessageIndex = self.viewModel.viewState.unreadIndicatorIndex?.intValue if let focusedMessageID = self.focusedMessageID {
?? (self.viewItems.count - self.unreadViewItems.count) self.scrollToInteraction(with: focusedMessageID, isAnimated: false, highlighted: true)
if unreadCount > 0, let viewItem = self.viewItems[ifValid: firstUnreadMessageIndex], let interactionID = viewItem.interaction.uniqueId {
self.scrollToInteraction(with: interactionID, position: .top, isAnimated: false)
self.unreadCountView.alpha = self.scrollButton.alpha
} else { } else {
self.scrollToBottom(isAnimated: false) let firstUnreadMessageIndex = self.viewModel.viewState.unreadIndicatorIndex?.intValue
?? (self.viewItems.count - self.unreadViewItems.count)
if unreadCount > 0, let viewItem = self.viewItems[ifValid: firstUnreadMessageIndex], let interactionID = viewItem.interaction.uniqueId {
self.scrollToInteraction(with: interactionID, position: .top, isAnimated: false)
self.unreadCountView.alpha = self.scrollButton.alpha
} else {
self.scrollToBottom(isAnimated: false)
}
} }
self.scrollButton.alpha = self.getScrollButtonOpacity() self.scrollButton.alpha = self.getScrollButtonOpacity()
} }
@ -251,6 +256,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
highlightFocusedMessageIfNeeded()
didFinishInitialLayout = true didFinishInitialLayout = true
markAllAsRead() markAllAsRead()
} }
@ -313,6 +319,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
} }
} }
private func highlightFocusedMessageIfNeeded() {
if let indexPath = focusedMessageIndexPath, let cell = messagesTableView.cellForRow(at: indexPath) as? VisibleMessageCell {
cell.highlithed()
focusedMessageIndexPath = nil
}
}
@objc func handleKeyboardWillChangeFrameNotification(_ notification: Notification) { @objc func handleKeyboardWillChangeFrameNotification(_ notification: Notification) {
guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return } guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return }
if (newHeight > 0 && baselineKeyboardHeight == 0) { if (newHeight > 0 && baselineKeyboardHeight == 0) {
@ -617,8 +630,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
scrollToInteraction(with: interactionID) scrollToInteraction(with: interactionID)
} }
func scrollToInteraction(with interactionID: String, position: UITableView.ScrollPosition = .middle, isAnimated: Bool = true) { func scrollToInteraction(with interactionID: String, position: UITableView.ScrollPosition = .middle, isAnimated: Bool = true, highlighted: Bool = false) {
guard let indexPath = viewModel.ensureLoadWindowContainsInteractionId(interactionID) else { return } guard let indexPath = viewModel.ensureLoadWindowContainsInteractionId(interactionID) else { return }
messagesTableView.scrollToRow(at: indexPath, at: position, animated: isAnimated) messagesTableView.scrollToRow(at: indexPath, at: position, animated: isAnimated)
if highlighted, let _ = messagesTableView.cellForRow(at: indexPath) as? VisibleMessageCell {
focusedMessageIndexPath = indexPath
}
} }
} }

@ -65,7 +65,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
lazy var bubbleView: UIView = { lazy var bubbleView: UIView = {
let result = UIView() let result = UIView()
result.layer.cornerRadius = VisibleMessageCell.smallCornerRadius result.layer.cornerRadius = VisibleMessageCell.largeCornerRadius
return result return result
}() }()
@ -431,10 +431,12 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
} }
private func updateBubbleViewCorners() { private func updateBubbleViewCorners() {
let maskPath = UIBezierPath(roundedRect: bubbleView.bounds, byRoundingCorners: getCornersToRound(), let cornersToRound = getCornersToRound()
let maskPath = UIBezierPath(roundedRect: bubbleView.bounds, byRoundingCorners: cornersToRound,
cornerRadii: CGSize(width: VisibleMessageCell.largeCornerRadius, height: VisibleMessageCell.largeCornerRadius)) cornerRadii: CGSize(width: VisibleMessageCell.largeCornerRadius, height: VisibleMessageCell.largeCornerRadius))
bubbleViewMaskLayer.path = maskPath.cgPath bubbleViewMaskLayer.path = maskPath.cgPath
bubbleView.layer.mask = bubbleViewMaskLayer bubbleView.layer.cornerRadius = VisibleMessageCell.largeCornerRadius
bubbleView.layer.maskedCorners = getCornerMask(from: cornersToRound)
} }
override func prepareForReuse() { override func prepareForReuse() {
@ -470,6 +472,16 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
return abs(v.x) > abs(v.y) // It has to be more horizontal than vertical return abs(v.x) > abs(v.y) // It has to be more horizontal than vertical
} else { } else {
return true return true
}
}
func highlithed() {
bubbleView.setShadow(radius: 6, opacity: 1, offset: .zero, color: Colors.accent.cgColor)
DispatchQueue.main.async {
UIView.animate(withDuration: 2) {
self.bubbleView.setShadow(radius: 0, opacity: 0, offset: .zero, color: UIColor.clear.cgColor)
}
} }
} }
@ -571,6 +583,19 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
return result return result
} }
private func getCornerMask(from rectCorner: UIRectCorner) -> CACornerMask {
var cornerMask = CACornerMask()
if rectCorner.contains(.allCorners) {
cornerMask = [ .layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
} else {
if rectCorner.contains(.topRight) { cornerMask.insert(.layerMaxXMinYCorner) }
if rectCorner.contains(.topLeft) { cornerMask.insert(.layerMinXMinYCorner) }
if rectCorner.contains(.bottomRight) { cornerMask.insert(.layerMaxXMaxYCorner) }
if rectCorner.contains(.bottomLeft) { cornerMask.insert(.layerMinXMaxYCorner) }
}
return cornerMask
}
private static func getFontSize(for viewItem: ConversationViewItem) -> CGFloat { private static func getFontSize(for viewItem: ConversationViewItem) -> CGFloat {
let baselineFontSize = Values.mediumFontSize let baselineFontSize = Values.mediumFontSize
switch viewItem.displayableBodyText?.jumbomojiCount { switch viewItem.displayableBodyText?.jumbomojiCount {

@ -156,7 +156,7 @@ extension GlobalSearchViewController {
case .messages: case .messages:
let sectionResults = searchResultSet.messages let sectionResults = searchResultSet.messages
guard let searchResult = sectionResults[safe: indexPath.row], let threadId = searchResult.thread.threadRecord.uniqueId, let thread = TSThread.fetch(uniqueId: threadId) else { return } guard let searchResult = sectionResults[safe: indexPath.row], let threadId = searchResult.thread.threadRecord.uniqueId, let thread = TSThread.fetch(uniqueId: threadId) else { return }
show(thread, highlightedMessageID: nil, animated: true) show(thread, highlightedMessageID: searchResult.messageId, animated: true)
} }
tableView.deselectRow(at: indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
} }

@ -82,7 +82,7 @@ class BaseVC : UIViewController {
headingImageView.image = UIImage(named: "SessionHeading")?.withRenderingMode(.alwaysTemplate) headingImageView.image = UIImage(named: "SessionHeading")?.withRenderingMode(.alwaysTemplate)
headingImageView.contentMode = .scaleAspectFit headingImageView.contentMode = .scaleAspectFit
headingImageView.set(.width, to: 150) headingImageView.set(.width, to: 150)
headingImageView.set(.height, to: Values.largeFontSize) headingImageView.set(.height, to: 18)
navigationItem.titleView = headingImageView navigationItem.titleView = headingImageView
} }

@ -120,11 +120,11 @@ public extension UIView {
return constraints return constraints
} }
func setShadow(radius: CGFloat = 2.0, opacity: CGFloat = 0.66, offset: CGPoint = .zero, color: CGColor = UIColor.black.cgColor) { func setShadow(radius: CGFloat = 2.0, opacity: Float = 0.66, offset: CGSize = .zero, color: CGColor = UIColor.black.cgColor) {
layer.shadowColor = UIColor.black.cgColor layer.shadowColor = color
layer.shadowRadius = 2.0 layer.shadowRadius = radius
layer.shadowOpacity = 0.66 layer.shadowOpacity = opacity
layer.shadowOffset = .zero layer.shadowOffset = offset
} }
} }

Loading…
Cancel
Save