diff --git a/Chatto/Source/ChatController/BaseChatViewController+Changes.swift b/Chatto/Source/ChatController/BaseChatViewController+Changes.swift index e666fc8..c8666c2 100644 --- a/Chatto/Source/ChatController/BaseChatViewController+Changes.swift +++ b/Chatto/Source/ChatController/BaseChatViewController+Changes.swift @@ -118,7 +118,8 @@ extension BaseChatViewController: ChatDataSourceDelegateProtocol { updateType: UpdateType, completion: () -> Void) { let shouldScrollToBottom = updateType != .Pagination && self.isScrolledAtBottom() - let oldRect = self.rectAtIndexPath(changes.movedIndexPaths.first?.indexPathOld) + let (oldReferenceIndexPath, newReferenceIndexPath) = self.referenceIndexPathsToRestoreScrollPositionOnUpdate(itemsBeforeUpdate: self.chatItemCompanionCollection, changes: changes) + let oldRect = self.rectAtIndexPath(oldReferenceIndexPath) let myCompletion = { // Found that cells may not match correct index paths here yet! (see comment below) // Waiting for next loop seems to fix the issue @@ -156,7 +157,7 @@ extension BaseChatViewController: ChatDataSourceDelegateProtocol { if shouldScrollToBottom { self.scrollToBottom(animated: updateType == .Normal) } else { - let newRect = self.rectAtIndexPath(changes.movedIndexPaths.first?.indexPathNew) + let newRect = self.rectAtIndexPath(newReferenceIndexPath) self.scrollToPreservePosition(oldRefRect: oldRect, newRefRect: newRect) } } diff --git a/Chatto/Source/ChatController/BaseChatViewController.swift b/Chatto/Source/ChatController/BaseChatViewController.swift index 0617d8c..33a30f4 100644 --- a/Chatto/Source/ChatController/BaseChatViewController.swift +++ b/Chatto/Source/ChatController/BaseChatViewController.swift @@ -187,16 +187,6 @@ public class BaseChatViewController: UIViewController, UICollectionViewDataSourc let presentersByCell = NSMapTable(keyOptions: .WeakMemory, valueOptions: .WeakMemory) var updateQueue: SerialTaskQueueProtocol = SerialTaskQueue() - public func createPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] { - assert(false, "Override in subclass") - return [ChatItemType: [ChatItemPresenterBuilderProtocol]]() - } - - public func createChatInputView() -> UIView { - assert(false, "Override in subclass") - return UIView() - } - /** - You can use a decorator to: - Provide the ChatCollectionViewLayout with margins between messages @@ -212,6 +202,28 @@ public class BaseChatViewController: UIViewController, UICollectionViewDataSourc } var layoutModel = ChatCollectionViewLayoutModel.createModel(0, itemsLayoutData: []) + + + // MARK: Subclass overrides + + public func createPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] { + assert(false, "Override in subclass") + return [ChatItemType: [ChatItemPresenterBuilderProtocol]]() + } + + public func createChatInputView() -> UIView { + assert(false, "Override in subclass") + return UIView() + } + + /** + When paginating up we need to change the scroll position as the content is pushed down. + We take distance to top from beforeUpdate indexPath and then we make afterUpdate indexPath to appear at the same distance + */ + public func referenceIndexPathsToRestoreScrollPositionOnUpdate(itemsBeforeUpdate itemsBeforeUpdate: ChatItemCompanionCollection, changes: CollectionChanges) -> (beforeUpdate: NSIndexPath?, afterUpdate: NSIndexPath?) { + let firstItemMoved = changes.movedIndexPaths.first + return (firstItemMoved?.indexPathOld, firstItemMoved?.indexPathNew) + } } extension BaseChatViewController { // Rotation diff --git a/Chatto/Source/ChatController/CollectionChanges.swift b/Chatto/Source/ChatController/CollectionChanges.swift index f6da357..5152859 100644 --- a/Chatto/Source/ChatController/CollectionChanges.swift +++ b/Chatto/Source/ChatController/CollectionChanges.swift @@ -28,25 +28,25 @@ public protocol UniqueIdentificable { var uid: String { get } } -struct CollectionChangeMove: Equatable, Hashable { - let indexPathOld: NSIndexPath - let indexPathNew: NSIndexPath - init(indexPathOld: NSIndexPath, indexPathNew: NSIndexPath) { +public struct CollectionChangeMove: Equatable, Hashable { + public let indexPathOld: NSIndexPath + public let indexPathNew: NSIndexPath + public init(indexPathOld: NSIndexPath, indexPathNew: NSIndexPath) { self.indexPathOld = indexPathOld self.indexPathNew = indexPathNew } - var hashValue: Int { return indexPathOld.hash ^ indexPathNew.hash } + public var hashValue: Int { return indexPathOld.hash ^ indexPathNew.hash } } -func == (lhs: CollectionChangeMove, rhs: CollectionChangeMove) -> Bool { +public func == (lhs: CollectionChangeMove, rhs: CollectionChangeMove) -> Bool { return lhs.indexPathOld == rhs.indexPathOld && lhs.indexPathNew == rhs.indexPathNew } -struct CollectionChanges { - let insertedIndexPaths: Set - let deletedIndexPaths: Set - let movedIndexPaths: [CollectionChangeMove] +public struct CollectionChanges { + public let insertedIndexPaths: Set + public let deletedIndexPaths: Set + public let movedIndexPaths: [CollectionChangeMove] init(insertedIndexPaths: Set, deletedIndexPaths: Set, movedIndexPaths: [CollectionChangeMove]) { self.insertedIndexPaths = insertedIndexPaths