minor improvements to reduce the database read on UI thread

pull/541/head
Ryan Zhao 3 years ago
parent 936fbd27c2
commit 2ae0ae40d4

@ -11,6 +11,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
let threadStartedAsMessageRequest: Bool let threadStartedAsMessageRequest: Bool
let focusedMessageID: String? // This is used for global search let focusedMessageID: String? // This is used for global search
var focusedMessageIndexPath: IndexPath? var focusedMessageIndexPath: IndexPath?
var initialUnreadCount: UInt = 0
var unreadViewItems: [ConversationViewItem] = [] var unreadViewItems: [ConversationViewItem] = []
var scrollButtonBottomConstraint: NSLayoutConstraint? var scrollButtonBottomConstraint: NSLayoutConstraint?
var scrollButtonMessageRequestsBottomConstraint: NSLayoutConstraint? var scrollButtonMessageRequestsBottomConstraint: NSLayoutConstraint?
@ -276,11 +277,10 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
self.threadStartedAsMessageRequest = thread.isMessageRequest() self.threadStartedAsMessageRequest = thread.isMessageRequest()
self.focusedMessageID = focusedMessageID self.focusedMessageID = focusedMessageID
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
var unreadCount: UInt = 0
Storage.read { transaction in Storage.read { transaction in
unreadCount = self.thread.unreadMessageCount(transaction: transaction) self.initialUnreadCount = self.thread.unreadMessageCount(transaction: transaction)
} }
let clampedUnreadCount = min(unreadCount, UInt(kConversationInitialMaxRangeSize), UInt(viewItems.endIndex)) let clampedUnreadCount = min(self.initialUnreadCount, UInt(kConversationInitialMaxRangeSize), UInt(viewItems.endIndex))
unreadViewItems = clampedUnreadCount != 0 ? [ConversationViewItem](viewItems[viewItems.endIndex - Int(clampedUnreadCount) ..< viewItems.endIndex]) : [] unreadViewItems = clampedUnreadCount != 0 ? [ConversationViewItem](viewItems[viewItems.endIndex - Int(clampedUnreadCount) ..< viewItems.endIndex]) : []
} }
@ -289,6 +289,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
} }
override func viewDidLoad() { override func viewDidLoad() {
SNLog("Ryan: Conversation VC starts loading at \(NSDate.ows_millisecondTimeStamp())")
super.viewDidLoad() super.viewDidLoad()
// Gradient // Gradient
setUpGradientBackground() setUpGradientBackground()
@ -391,27 +392,26 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
if let v2OpenGroup = Storage.shared.getV2OpenGroup(for: thread.uniqueId!) { if let v2OpenGroup = Storage.shared.getV2OpenGroup(for: thread.uniqueId!) {
OpenGroupAPIV2.getMemberCount(for: v2OpenGroup.room, on: v2OpenGroup.server).retainUntilComplete() OpenGroupAPIV2.getMemberCount(for: v2OpenGroup.room, on: v2OpenGroup.server).retainUntilComplete()
} }
SNLog("Ryan: Conversation VC ends loading at \(NSDate.ows_millisecondTimeStamp())")
} }
override func viewDidLayoutSubviews() { override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
if !didFinishInitialLayout { if !didFinishInitialLayout {
// Scroll to the last unread message if possible; otherwise scroll to the bottom. // Scroll to the last unread message if possible; otherwise scroll to the bottom.
var unreadCount: UInt = 0
Storage.read { transaction in
unreadCount = self.thread.unreadMessageCount(transaction: transaction)
}
// When the unread message count is more than the number of view items of a page, // When the unread message count is more than the number of view items of a page,
// the screen will scroll to the bottom instead of the first unread message. // the screen will scroll to the bottom instead of the first unread message.
// 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 {
SNLog("Ryan: Conversation VC starts layout subviews at \(NSDate.ows_millisecondTimeStamp())")
if let focusedMessageID = self.focusedMessageID { if let focusedMessageID = self.focusedMessageID {
self.scrollToInteraction(with: focusedMessageID, isAnimated: false, highlighted: true) self.scrollToInteraction(with: focusedMessageID, isAnimated: false, highlighted: true)
} else { } else {
let firstUnreadMessageIndex = self.viewModel.viewState.unreadIndicatorIndex?.intValue let firstUnreadMessageIndex = self.viewModel.viewState.unreadIndicatorIndex?.intValue
?? (self.viewItems.count - self.unreadViewItems.count) ?? (self.viewItems.count - self.unreadViewItems.count)
if unreadCount > 0, let viewItem = self.viewItems[ifValid: firstUnreadMessageIndex], let interactionID = viewItem.interaction.uniqueId { if self.initialUnreadCount > 0, let viewItem = self.viewItems[ifValid: firstUnreadMessageIndex], let interactionID = viewItem.interaction.uniqueId {
self.scrollToInteraction(with: interactionID, position: .top, isAnimated: false) self.scrollToInteraction(with: interactionID, position: .top, isAnimated: false)
self.unreadCountView.alpha = self.scrollButton.alpha self.unreadCountView.alpha = self.scrollButton.alpha
} else { } else {
@ -419,11 +419,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
} }
} }
self.scrollButton.alpha = self.getScrollButtonOpacity() self.scrollButton.alpha = self.getScrollButtonOpacity()
SNLog("Ryan: Conversation VC ends layout subviews at \(NSDate.ows_millisecondTimeStamp())")
} }
} }
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
SNLog("Ryan: Conversation VC did appear at \(NSDate.ows_millisecondTimeStamp())")
super.viewDidAppear(animated) super.viewDidAppear(animated)
highlightFocusedMessageIfNeeded() highlightFocusedMessageIfNeeded()
didFinishInitialLayout = true didFinishInitialLayout = true
@ -777,6 +779,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
let isMainAppAndActive = CurrentAppContext().isMainAppAndActive let isMainAppAndActive = CurrentAppContext().isMainAppAndActive
guard isMainAppAndActive && viewModel.canLoadMoreItems() && !isLoadingMore guard isMainAppAndActive && viewModel.canLoadMoreItems() && !isLoadingMore
&& messagesTableView.contentOffset.y < ConversationVC.loadMoreThreshold else { return } && messagesTableView.contentOffset.y < ConversationVC.loadMoreThreshold else { return }
print("Ryan: auto loading more")
isLoadingMore = true isLoadingMore = true
viewModel.loadAnotherPageOfMessages() viewModel.loadAnotherPageOfMessages()
} }

@ -1,6 +1,7 @@
final class QuoteView : UIView { final class QuoteView : UIView {
private let mode: Mode private let mode: Mode
private let thread: TSThread
private let direction: Direction private let direction: Direction
private let hInset: CGFloat private let hInset: CGFloat
private let maxWidth: CGFloat private let maxWidth: CGFloat
@ -34,25 +35,6 @@ final class QuoteView : UIView {
} }
} }
private var threadID: String {
switch mode {
case .regular(let viewItem): return viewItem.interaction.uniqueThreadId
case .draft(let model): return model.threadId
}
}
private var isGroupThread: Bool {
switch mode {
case .regular(let viewItem): return viewItem.isGroupThread
case .draft(let model):
var result = false
Storage.read { transaction in
result = TSThread.fetch(uniqueId: model.threadId, transaction: transaction)?.isGroupThread() ?? false
}
return result
}
}
private var authorID: String { private var authorID: String {
switch mode { switch mode {
case .regular(let viewItem): return viewItem.quotedReply!.authorId case .regular(let viewItem): return viewItem.quotedReply!.authorId
@ -93,8 +75,9 @@ final class QuoteView : UIView {
static let cancelButtonSize: CGFloat = 33 static let cancelButtonSize: CGFloat = 33
// MARK: Lifecycle // MARK: Lifecycle
init(for viewItem: ConversationViewItem, direction: Direction, hInset: CGFloat, maxWidth: CGFloat) { init(for viewItem: ConversationViewItem, in thread: TSThread?, direction: Direction, hInset: CGFloat, maxWidth: CGFloat) {
self.mode = .regular(viewItem) self.mode = .regular(viewItem)
self.thread = thread ?? TSThread.fetch(uniqueId: viewItem.interaction.uniqueThreadId)!
self.maxWidth = maxWidth self.maxWidth = maxWidth
self.direction = direction self.direction = direction
self.hInset = hInset self.hInset = hInset
@ -105,6 +88,7 @@ final class QuoteView : UIView {
init(for model: OWSQuotedReplyModel, direction: Direction, hInset: CGFloat, maxWidth: CGFloat, delegate: QuoteViewDelegate) { init(for model: OWSQuotedReplyModel, direction: Direction, hInset: CGFloat, maxWidth: CGFloat, delegate: QuoteViewDelegate) {
self.mode = .draft(model) self.mode = .draft(model)
self.thread = TSThread.fetch(uniqueId: model.threadId)!
self.maxWidth = maxWidth self.maxWidth = maxWidth
self.direction = direction self.direction = direction
self.hInset = hInset self.hInset = hInset
@ -188,16 +172,15 @@ final class QuoteView : UIView {
bodyLabel.lineBreakMode = .byTruncatingTail bodyLabel.lineBreakMode = .byTruncatingTail
let isOutgoing = (direction == .outgoing) let isOutgoing = (direction == .outgoing)
bodyLabel.font = .systemFont(ofSize: Values.smallFontSize) bodyLabel.font = .systemFont(ofSize: Values.smallFontSize)
bodyLabel.attributedText = given(body) { MentionUtilities.highlightMentions(in: $0, isOutgoingMessage: isOutgoing, threadID: threadID, attributes: [:]) } bodyLabel.attributedText = given(body) { MentionUtilities.highlightMentions(in: $0, isOutgoingMessage: isOutgoing, threadID: thread.uniqueId!, attributes: [:]) } ?? given(attachments.first?.contentType) { NSAttributedString(string: MIMETypeUtil.isAudio($0) ? "Audio" : "Document") } ?? NSAttributedString(string: "Document")
?? given(attachments.first?.contentType) { NSAttributedString(string: MIMETypeUtil.isAudio($0) ? "Audio" : "Document") } ?? NSAttributedString(string: "Document")
bodyLabel.textColor = textColor bodyLabel.textColor = textColor
let bodyLabelSize = bodyLabel.systemLayoutSizeFitting(availableSpace) let bodyLabelSize = bodyLabel.systemLayoutSizeFitting(availableSpace)
// Label stack view // Label stack view
var authorLabelHeight: CGFloat? var authorLabelHeight: CGFloat?
if isGroupThread { if let groupThread = thread as? TSGroupThread {
let authorLabel = UILabel() let authorLabel = UILabel()
authorLabel.lineBreakMode = .byTruncatingTail authorLabel.lineBreakMode = .byTruncatingTail
let context: Contact.Context = (TSGroupThread.fetch(uniqueId: threadID)?.isOpenGroup == true) ? .openGroup : .regular let context: Contact.Context = groupThread.isOpenGroup ? .openGroup : .regular
authorLabel.text = Storage.shared.getContact(with: authorID)?.displayName(for: context) ?? authorID authorLabel.text = Storage.shared.getContact(with: authorID)?.displayName(for: context) ?? authorID
authorLabel.textColor = textColor authorLabel.textColor = textColor
authorLabel.font = .boldSystemFont(ofSize: Values.smallFontSize) authorLabel.font = .boldSystemFont(ofSize: Values.smallFontSize)
@ -225,7 +208,7 @@ final class QuoteView : UIView {
// Constraints // Constraints
contentView.addSubview(mainStackView) contentView.addSubview(mainStackView)
mainStackView.pin(to: contentView) mainStackView.pin(to: contentView)
if !isGroupThread { if !thread.isGroupThread() {
bodyLabel.set(.width, to: bodyLabelSize.width) bodyLabel.set(.width, to: bodyLabelSize.width)
} }
let bodyLabelHeight = bodyLabelSize.height.clamp(0, maxBodyLabelHeight) let bodyLabelHeight = bodyLabelSize.height.clamp(0, maxBodyLabelHeight)

@ -335,7 +335,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
if viewItem.quotedReply != nil { if viewItem.quotedReply != nil {
let direction: QuoteView.Direction = isOutgoing ? .outgoing : .incoming let direction: QuoteView.Direction = isOutgoing ? .outgoing : .incoming
let hInset: CGFloat = 2 let hInset: CGFloat = 2
let quoteView = QuoteView(for: viewItem, direction: direction, hInset: hInset, maxWidth: maxWidth) let quoteView = QuoteView(for: viewItem, in: thread, direction: direction, hInset: hInset, maxWidth: maxWidth)
let quoteViewContainer = UIView(wrapping: quoteView, withInsets: UIEdgeInsets(top: 0, leading: hInset, bottom: 0, trailing: hInset)) let quoteViewContainer = UIView(wrapping: quoteView, withInsets: UIEdgeInsets(top: 0, leading: hInset, bottom: 0, trailing: hInset))
stackView.addArrangedSubview(quoteViewContainer) stackView.addArrangedSubview(quoteViewContainer)
} }

Loading…
Cancel
Save