diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 0e70106cf..ea132407e 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5063,7 +5063,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5132,7 +5132,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5193,7 +5193,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5263,7 +5263,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6148,7 +6148,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6216,7 +6216,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 270; + CURRENT_PROJECT_VERSION = 272; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 8b2d9b960..61ac11d40 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -18,10 +18,11 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } func handleScrollToBottomButtonTapped() { - // The tableview's content size will be calculated by the estimated height of cells, - // so the result may be inaccurate before all the cells are loaded. - // Use this scroll to the last row instead. - messagesTableView.scrollToRow(at: IndexPath(row: viewItems.count-1, section: 0), at: .top, animated: true) + // The table view's content size is calculated by the estimated height of cells, + // so the result may be inaccurate before all the cells are loaded. Use this + // to scroll to the last row instead. + let indexPath = IndexPath(row: viewItems.count - 1, section: 0) + messagesTableView.scrollToRow(at: indexPath, at: .top, animated: true) } // MARK: Blocking diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index baa5ec147..ab678dec6 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -149,6 +149,8 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat static let scrollButtonFullVisibilityThreshold: CGFloat = 80 /// The button will be invisible until the user has scrolled at least this amount from the bottom of the table view. static let scrollButtonNoVisibilityThreshold: CGFloat = 20 + /// Automatically scroll to the bottom of the conversation when sending a message if the scroll distance from the bottom is less than this number. + static let scrollToBottomMargin: CGFloat = 40 // MARK: Lifecycle init(thread: TSThread, focusedMessageID: String? = nil) { @@ -222,13 +224,14 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat Storage.read { transaction in unreadCount = self.thread.unreadMessageCount(transaction: transaction) } - // When the unread message count is more than the number of a page of viewItems, - // the screen will scroll to bottom instead of the correct first unread message. - // The unreadIndicatorIndex is calculated during loading the viewItems, it is + // 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. + // unreadIndicatorIndex is calculated during loading of the viewItems, so it's // supposed to be accurate. DispatchQueue.main.async { - let unreadIndicatorIndex = self.viewModel.viewState.unreadIndicatorIndex?.intValue ?? (self.viewItems.count - self.unreadViewItems.count) - if unreadCount > 0, let viewItem = self.viewItems[ifValid: unreadIndicatorIndex], let interactionID = viewItem.interaction.uniqueId { + 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 { @@ -350,11 +353,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat if update.viewItem?.interaction is TSOutgoingMessage { shouldScrollToBottom = true } else { - shouldScrollToBottom = (self.lastPageTop - self.messagesTableView.contentOffset.y) <= 0 + let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) + shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin } case .update: self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade) - shouldScrollToBottom = (self.lastPageTop - self.messagesTableView.contentOffset.y) <= 0 + let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) + shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin default: preconditionFailure() } } diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m index 6d5d17ab7..81bf7beb1 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m @@ -147,9 +147,10 @@ NS_ASSUME_NONNULL_BEGIN BOOL areAllAttachmentsDownloaded = YES; for (NSString *attachmentId in self.attachmentIds) { TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; - // If the attachment download is failed, we can mark this message as read. + // If the attachment download failed, we can mark this message as read. // Otherwise, this message will never be marked as read. - if ([attachment isKindOfClass:[TSAttachmentPointer class]] && ((TSAttachmentPointer *)attachment).state == TSAttachmentPointerStateFailed) { + if ([attachment isKindOfClass:[TSAttachmentPointer class]] + && ((TSAttachmentPointer *)attachment).state == TSAttachmentPointerStateFailed) { continue; } areAllAttachmentsDownloaded = areAllAttachmentsDownloaded && attachment.isDownloaded;