From ac60d190405a36853643998b9da00b5fd06fecac Mon Sep 17 00:00:00 2001
From: Merrick Sapsford <merrick@sapsford.tech>
Date: Mon, 4 May 2020 08:06:42 +0200
Subject: [PATCH 1/5] Fix insertion below current index

---
 Sources/Pageboy/PageboyViewController+Updating.swift | 12 +++++++++++-
 Sources/Pageboy/PageboyViewController.swift          |  4 +++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/Sources/Pageboy/PageboyViewController+Updating.swift b/Sources/Pageboy/PageboyViewController+Updating.swift
index a3e749a3..6abfdb40 100644
--- a/Sources/Pageboy/PageboyViewController+Updating.swift
+++ b/Sources/Pageboy/PageboyViewController+Updating.swift
@@ -20,6 +20,11 @@ extension PageboyViewController {
         case scrollToUpdate
         case scrollTo(index: PageIndex)
     }
+    
+    internal enum UpdateOperation {
+        case insert
+        case delete
+    }
 }
 
 // MARK: - Page Updates
@@ -27,6 +32,7 @@ internal extension PageboyViewController {
     
     func performUpdates(for newIndex: PageIndex?,
                         viewController: UIViewController?,
+                        operation: UpdateOperation,
                         updateBehavior: PageUpdateBehavior,
                         indexOperation: (_ currentIndex: PageIndex, _ newIndex: PageIndex) -> Void) {
         guard let newIndex = newIndex, let viewController = viewController else { // no view controller - reset
@@ -49,7 +55,11 @@ internal extension PageboyViewController {
             return
         }
         
-        if newIndex == currentIndex { // currently on the page for the update.
+        // If we are inserting a page that is lower/equal to the current index
+        // we have to move the current page up therefore we can't just cross-dissolve.
+        let isInsertionThatRequiresMoving = operation == .insert && newIndex <= currentIndex
+        
+        if !isInsertionThatRequiresMoving && newIndex == currentIndex { // currently on the page for the update.
             pageViewController?.view.crossDissolve(during: { [weak self, viewController] in
                 self?.updateViewControllers(to: [viewController],
                                             animated: false,
diff --git a/Sources/Pageboy/PageboyViewController.swift b/Sources/Pageboy/PageboyViewController.swift
index b3189d56..b9f2473a 100755
--- a/Sources/Pageboy/PageboyViewController.swift
+++ b/Sources/Pageboy/PageboyViewController.swift
@@ -290,10 +290,11 @@ open class PageboyViewController: UIViewController {
 
         performUpdates(for: index,
                         viewController: newViewController,
+                        operation: .insert,
                         updateBehavior: updateBehavior,
                         indexOperation: { (index, newIndex) in
 
-                        if index > newIndex {
+                        if index >= newIndex {
                             currentIndex = index + 1
                         }
         })
@@ -330,6 +331,7 @@ open class PageboyViewController: UIViewController {
 
             performUpdates(for: newIndex,
                            viewController: newViewController,
+                           operation: .delete,
                            updateBehavior: updateBehavior,
                            indexOperation: { (index, newIndex) in
 

From 5a2237c366564c925475dbcd6051ef35dba84247 Mon Sep 17 00:00:00 2001
From: Merrick Sapsford <merrick@sapsford.tech>
Date: Mon, 4 May 2020 08:56:31 +0200
Subject: [PATCH 2/5] Fix deletion of upper index causing page index corruption

---
 .../PageboyViewController+Updating.swift      | 22 ++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/Sources/Pageboy/PageboyViewController+Updating.swift b/Sources/Pageboy/PageboyViewController+Updating.swift
index 6abfdb40..1eeeb7da 100644
--- a/Sources/Pageboy/PageboyViewController+Updating.swift
+++ b/Sources/Pageboy/PageboyViewController+Updating.swift
@@ -70,13 +70,29 @@ internal extension PageboyViewController {
         } else { // update is happening on some other page.
             indexOperation(currentIndex, newIndex)
             
+            // If we are deleting, check if the new index is greater than the current. If it is then we
+            // dont need to do anything...
+            if operation == .delete && newIndex > currentIndex {
+                return
+            }
+            
             // Reload current view controller in UIPageViewController if insertion index is next/previous page.
             if pageIndex(newIndex, isNextTo: currentIndex) {
-                guard let currentViewController = currentViewController else {
-                    return
+                
+                let newViewController: UIViewController
+                switch operation {
+                    
+                case .insert:
+                    guard let currentViewController = currentViewController else {
+                        return
+                    }
+                    newViewController = currentViewController
+                    
+                case .delete:
+                    newViewController = viewController
                 }
                 
-                updateViewControllers(to: [currentViewController], animated: false, async: true, force: false, completion: { [weak self, newIndex, updateBehavior] _ in
+                updateViewControllers(to: [newViewController], animated: false, async: true, force: false, completion: { [weak self, newIndex, updateBehavior] _ in
                     self?.performScrollUpdate(to: newIndex, behavior: updateBehavior)
                 })
             } else { // Otherwise just perform scroll update

From 0830acd64f9decc4fe34fe153646c7f938abc45b Mon Sep 17 00:00:00 2001
From: Merrick Sapsford <merrick@sapsford.tech>
Date: Mon, 4 May 2020 09:05:02 +0200
Subject: [PATCH 3/5] Clean up

---
 .../Pageboy/PageboyViewController+Updating.swift  | 15 +++++++--------
 Sources/Pageboy/PageboyViewController.swift       |  6 ++----
 2 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/Sources/Pageboy/PageboyViewController+Updating.swift b/Sources/Pageboy/PageboyViewController+Updating.swift
index 1eeeb7da..a5d69be1 100644
--- a/Sources/Pageboy/PageboyViewController+Updating.swift
+++ b/Sources/Pageboy/PageboyViewController+Updating.swift
@@ -32,8 +32,7 @@ internal extension PageboyViewController {
     
     func performUpdates(for newIndex: PageIndex?,
                         viewController: UIViewController?,
-                        operation: UpdateOperation,
-                        updateBehavior: PageUpdateBehavior,
+                        update: (operation: UpdateOperation, behavior: PageUpdateBehavior),
                         indexOperation: (_ currentIndex: PageIndex, _ newIndex: PageIndex) -> Void) {
         guard let newIndex = newIndex, let viewController = viewController else { // no view controller - reset
             updateViewControllers(to: [UIViewController()],
@@ -57,7 +56,7 @@ internal extension PageboyViewController {
         
         // If we are inserting a page that is lower/equal to the current index
         // we have to move the current page up therefore we can't just cross-dissolve.
-        let isInsertionThatRequiresMoving = operation == .insert && newIndex <= currentIndex
+        let isInsertionThatRequiresMoving = update.operation == .insert && newIndex <= currentIndex
         
         if !isInsertionThatRequiresMoving && newIndex == currentIndex { // currently on the page for the update.
             pageViewController?.view.crossDissolve(during: { [weak self, viewController] in
@@ -72,7 +71,7 @@ internal extension PageboyViewController {
             
             // If we are deleting, check if the new index is greater than the current. If it is then we
             // dont need to do anything...
-            if operation == .delete && newIndex > currentIndex {
+            if update.operation == .delete && newIndex > currentIndex {
                 return
             }
             
@@ -80,7 +79,7 @@ internal extension PageboyViewController {
             if pageIndex(newIndex, isNextTo: currentIndex) {
                 
                 let newViewController: UIViewController
-                switch operation {
+                switch update.operation {
                     
                 case .insert:
                     guard let currentViewController = currentViewController else {
@@ -92,11 +91,11 @@ internal extension PageboyViewController {
                     newViewController = viewController
                 }
                 
-                updateViewControllers(to: [newViewController], animated: false, async: true, force: false, completion: { [weak self, newIndex, updateBehavior] _ in
-                    self?.performScrollUpdate(to: newIndex, behavior: updateBehavior)
+                updateViewControllers(to: [newViewController], animated: false, async: true, force: false, completion: { [weak self, newIndex, update] _ in
+                    self?.performScrollUpdate(to: newIndex, behavior: update.behavior)
                 })
             } else { // Otherwise just perform scroll update
-                performScrollUpdate(to: newIndex, behavior: updateBehavior)
+                performScrollUpdate(to: newIndex, behavior: update.behavior)
             }
         }
     }
diff --git a/Sources/Pageboy/PageboyViewController.swift b/Sources/Pageboy/PageboyViewController.swift
index b9f2473a..44bd3c11 100755
--- a/Sources/Pageboy/PageboyViewController.swift
+++ b/Sources/Pageboy/PageboyViewController.swift
@@ -290,8 +290,7 @@ open class PageboyViewController: UIViewController {
 
         performUpdates(for: index,
                         viewController: newViewController,
-                        operation: .insert,
-                        updateBehavior: updateBehavior,
+                        update: (operation: .insert, behavior: updateBehavior),
                         indexOperation: { (index, newIndex) in
 
                         if index >= newIndex {
@@ -331,8 +330,7 @@ open class PageboyViewController: UIViewController {
 
             performUpdates(for: newIndex,
                            viewController: newViewController,
-                           operation: .delete,
-                           updateBehavior: updateBehavior,
+                           update: (operation: .delete, behavior: updateBehavior),
                            indexOperation: { (index, newIndex) in
 
                             if index > newIndex {

From c32a8e5db56c192db585cb44930d5cc760a57d25 Mon Sep 17 00:00:00 2001
From: Merrick Sapsford <merrick@sapsford.tech>
Date: Mon, 4 May 2020 09:07:08 +0200
Subject: [PATCH 4/5] Fix indentation

---
 Sources/Pageboy/PageboyViewController.swift | 33 +++++++++++----------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/Sources/Pageboy/PageboyViewController.swift b/Sources/Pageboy/PageboyViewController.swift
index 44bd3c11..3e38db6b 100755
--- a/Sources/Pageboy/PageboyViewController.swift
+++ b/Sources/Pageboy/PageboyViewController.swift
@@ -276,28 +276,29 @@ open class PageboyViewController: UIViewController {
     ///   - updateBehavior: Behavior to execute after the page was inserted.
     open func insertPage(at index: PageIndex,
                          then updateBehavior: PageUpdateBehavior = .scrollToUpdate) {
-    verifyNewPageCount(then: { (oldPageCount, newPageCount) in
+        
+        verifyNewPageCount(then: { (oldPageCount, newPageCount) in
         assert(newPageCount > oldPageCount,
-                "Attempt to insert page at \(index) but there are only \(newPageCount) pages after the update")
+                    "Attempt to insert page at \(index) but there are only \(newPageCount) pages after the update")
 
-        guard let newViewController = dataSource?.viewController(for: self, at: index) else {
-            assertionFailure("Expected to find inserted UIViewController at page \(index)")
-            return
-        }
+            guard let newViewController = dataSource?.viewController(for: self, at: index) else {
+                assertionFailure("Expected to find inserted UIViewController at page \(index)")
+                return
+            }
 
-        viewControllerCount = newPageCount
-        viewControllerIndexMap.removeAll()
+            viewControllerCount = newPageCount
+            viewControllerIndexMap.removeAll()
 
-        performUpdates(for: index,
-                        viewController: newViewController,
-                        update: (operation: .insert, behavior: updateBehavior),
-                        indexOperation: { (index, newIndex) in
+            performUpdates(for: index,
+                            viewController: newViewController,
+                            update: (operation: .insert, behavior: updateBehavior),
+                            indexOperation: { (index, newIndex) in
 
-                        if index >= newIndex {
-                            currentIndex = index + 1
-                        }
+                            if index >= newIndex {
+                                currentIndex = index + 1
+                            }
+            })
         })
-    })
     }
     
     /// Delete an existing page from the page view controller.

From 0847daef1232f542b5678cf64d12ef37a9c44649 Mon Sep 17 00:00:00 2001
From: Merrick Sapsford <merrick@sapsford.tech>
Date: Mon, 4 May 2020 09:15:48 +0200
Subject: [PATCH 5/5] Fix interaction issues when dynamically updating

---
 Sources/Pageboy.xcodeproj/project.pbxproj     | 12 ++++-----
 .../PageboyViewController+Updating.swift      | 13 +++++++---
 Sources/Pageboy/PageboyViewController.swift   | 26 +++++++++++--------
 ...y.swift => UIScrollView+Interaction.swift} |  7 ++++-
 4 files changed, 36 insertions(+), 22 deletions(-)
 rename Sources/Pageboy/Utilities/Extensions/{UIScrollView+ScrollActivity.swift => UIScrollView+Interaction.swift} (67%)

diff --git a/Sources/Pageboy.xcodeproj/project.pbxproj b/Sources/Pageboy.xcodeproj/project.pbxproj
index 005aef14..378435f2 100755
--- a/Sources/Pageboy.xcodeproj/project.pbxproj
+++ b/Sources/Pageboy.xcodeproj/project.pbxproj
@@ -9,8 +9,8 @@
 /* Begin PBXBuildFile section */
 		460906B7222A785E005474BF /* WeakContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 460906B6222A785E005474BF /* WeakContainer.swift */; };
 		460906B9222A79F6005474BF /* IndexedObjectMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 460906B8222A79F6005474BF /* IndexedObjectMap.swift */; };
-		461D6DF1201795A100E0CDEE /* UIScrollView+ScrollActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D6DF0201795A100E0CDEE /* UIScrollView+ScrollActivity.swift */; };
-		461D6DF2201795A100E0CDEE /* UIScrollView+ScrollActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D6DF0201795A100E0CDEE /* UIScrollView+ScrollActivity.swift */; };
+		461D6DF1201795A100E0CDEE /* UIScrollView+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D6DF0201795A100E0CDEE /* UIScrollView+Interaction.swift */; };
+		461D6DF2201795A100E0CDEE /* UIScrollView+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D6DF0201795A100E0CDEE /* UIScrollView+Interaction.swift */; };
 		462A65DD2000FCAA0051C79C /* UIView+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462A65D92000FCAA0051C79C /* UIView+Localization.swift */; };
 		462A65DE2000FCAA0051C79C /* UIView+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462A65D92000FCAA0051C79C /* UIView+Localization.swift */; };
 		462A65DF2000FCAA0051C79C /* UIView+AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462A65DA2000FCAA0051C79C /* UIView+AutoLayout.swift */; };
@@ -85,7 +85,7 @@
 /* Begin PBXFileReference section */
 		460906B6222A785E005474BF /* WeakContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakContainer.swift; sourceTree = "<group>"; };
 		460906B8222A79F6005474BF /* IndexedObjectMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexedObjectMap.swift; sourceTree = "<group>"; };
-		461D6DF0201795A100E0CDEE /* UIScrollView+ScrollActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+ScrollActivity.swift"; sourceTree = "<group>"; };
+		461D6DF0201795A100E0CDEE /* UIScrollView+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Interaction.swift"; sourceTree = "<group>"; };
 		462A65D92000FCAA0051C79C /* UIView+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Localization.swift"; sourceTree = "<group>"; };
 		462A65DA2000FCAA0051C79C /* UIView+AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+AutoLayout.swift"; sourceTree = "<group>"; };
 		462A65DB2000FCAA0051C79C /* UIApplication+SafeShared.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+SafeShared.swift"; sourceTree = "<group>"; };
@@ -160,7 +160,7 @@
 				462A65DA2000FCAA0051C79C /* UIView+AutoLayout.swift */,
 				462A65DB2000FCAA0051C79C /* UIApplication+SafeShared.swift */,
 				462A65DC2000FCAA0051C79C /* UIPageViewController+ScrollView.swift */,
-				461D6DF0201795A100E0CDEE /* UIScrollView+ScrollActivity.swift */,
+				461D6DF0201795A100E0CDEE /* UIScrollView+Interaction.swift */,
 				462D03DE2091D3AB0033C710 /* UIView+Animation.swift */,
 				BB5277382211308B003695BB /* DispatchQueue+main.swift */,
 			);
@@ -502,7 +502,7 @@
 				462A65E32000FCAA0051C79C /* UIPageViewController+ScrollView.swift in Sources */,
 				460906B9222A79F6005474BF /* IndexedObjectMap.swift in Sources */,
 				46ADAAC2208F7E8500974529 /* TransitionOperation.swift in Sources */,
-				461D6DF1201795A100E0CDEE /* UIScrollView+ScrollActivity.swift in Sources */,
+				461D6DF1201795A100E0CDEE /* UIScrollView+Interaction.swift in Sources */,
 				462A65DF2000FCAA0051C79C /* UIView+AutoLayout.swift in Sources */,
 				46ADAAC8208F7EB200974529 /* PageboyViewController+Updating.swift in Sources */,
 				BB5277392211308B003695BB /* DispatchQueue+main.swift in Sources */,
@@ -550,7 +550,7 @@
 				464ADF562097565D00929AFB /* Page.swift in Sources */,
 				46ADAAB9208F7E1500974529 /* PageboyViewController+AutoScrolling.swift in Sources */,
 				462A65E42000FCAA0051C79C /* UIPageViewController+ScrollView.swift in Sources */,
-				461D6DF2201795A100E0CDEE /* UIScrollView+ScrollActivity.swift in Sources */,
+				461D6DF2201795A100E0CDEE /* UIScrollView+Interaction.swift in Sources */,
 				46ADAAC3208F7E8500974529 /* TransitionOperation.swift in Sources */,
 				462A65E02000FCAA0051C79C /* UIView+AutoLayout.swift in Sources */,
 				46ADAAC9208F7EB200974529 /* PageboyViewController+Updating.swift in Sources */,
diff --git a/Sources/Pageboy/PageboyViewController+Updating.swift b/Sources/Pageboy/PageboyViewController+Updating.swift
index a5d69be1..d7b91353 100644
--- a/Sources/Pageboy/PageboyViewController+Updating.swift
+++ b/Sources/Pageboy/PageboyViewController+Updating.swift
@@ -33,13 +33,14 @@ internal extension PageboyViewController {
     func performUpdates(for newIndex: PageIndex?,
                         viewController: UIViewController?,
                         update: (operation: UpdateOperation, behavior: PageUpdateBehavior),
-                        indexOperation: (_ currentIndex: PageIndex, _ newIndex: PageIndex) -> Void) {
+                        indexOperation: (_ currentIndex: PageIndex, _ newIndex: PageIndex) -> Void,
+                        completion: ((Bool) -> Void)?) {
         guard let newIndex = newIndex, let viewController = viewController else { // no view controller - reset
             updateViewControllers(to: [UIViewController()],
                                   animated: false,
                                   async: false,
                                   force: false,
-                                  completion: nil)
+                                  completion: completion)
             self.currentIndex = nil
             return
         }
@@ -49,7 +50,7 @@ internal extension PageboyViewController {
                                   animated: false,
                                   async: false,
                                   force: false,
-                                  completion: nil)
+                                  completion: completion)
             self.currentIndex = newIndex
             return
         }
@@ -64,7 +65,7 @@ internal extension PageboyViewController {
                                             animated: false,
                                             async: true,
                                             force: false,
-                                            completion: nil)
+                                            completion: completion)
             })
         } else { // update is happening on some other page.
             indexOperation(currentIndex, newIndex)
@@ -72,6 +73,7 @@ internal extension PageboyViewController {
             // If we are deleting, check if the new index is greater than the current. If it is then we
             // dont need to do anything...
             if update.operation == .delete && newIndex > currentIndex {
+                completion?(true)
                 return
             }
             
@@ -83,6 +85,7 @@ internal extension PageboyViewController {
                     
                 case .insert:
                     guard let currentViewController = currentViewController else {
+                        completion?(true)
                         return
                     }
                     newViewController = currentViewController
@@ -93,9 +96,11 @@ internal extension PageboyViewController {
                 
                 updateViewControllers(to: [newViewController], animated: false, async: true, force: false, completion: { [weak self, newIndex, update] _ in
                     self?.performScrollUpdate(to: newIndex, behavior: update.behavior)
+                    completion?(true)
                 })
             } else { // Otherwise just perform scroll update
                 performScrollUpdate(to: newIndex, behavior: update.behavior)
+                completion?(true)
             }
         }
     }
diff --git a/Sources/Pageboy/PageboyViewController.swift b/Sources/Pageboy/PageboyViewController.swift
index 3e38db6b..664565f3 100755
--- a/Sources/Pageboy/PageboyViewController.swift
+++ b/Sources/Pageboy/PageboyViewController.swift
@@ -288,15 +288,17 @@ open class PageboyViewController: UIViewController {
 
             viewControllerCount = newPageCount
             viewControllerIndexMap.removeAll()
-
-            performUpdates(for: index,
-                            viewController: newViewController,
-                            update: (operation: .insert, behavior: updateBehavior),
-                            indexOperation: { (index, newIndex) in
-
+            
+            pageViewController?.scrollView?.cancelTouches()
+            view.isUserInteractionEnabled = false
+            performUpdates(for: index, viewController: newViewController,
+                           update: (operation: .insert, behavior: updateBehavior),
+                           indexOperation: { (index, newIndex) in
                             if index >= newIndex {
                                 currentIndex = index + 1
-                            }
+                            }},
+                           completion: { (_) in
+                            self.view.isUserInteractionEnabled = true
             })
         })
     }
@@ -329,14 +331,16 @@ open class PageboyViewController: UIViewController {
             viewControllerCount = newPageCount
             viewControllerIndexMap.removeAll()
 
-            performUpdates(for: newIndex,
-                           viewController: newViewController,
+            pageViewController?.scrollView?.cancelTouches()
+            view.isUserInteractionEnabled = false
+            performUpdates(for: newIndex, viewController: newViewController,
                            update: (operation: .delete, behavior: updateBehavior),
                            indexOperation: { (index, newIndex) in
-
                             if index > newIndex {
                                 currentIndex = index - 1
-                            }
+                            }},
+                           completion: { (_) in
+                            self.view.isUserInteractionEnabled = true
             })
         })
     }
diff --git a/Sources/Pageboy/Utilities/Extensions/UIScrollView+ScrollActivity.swift b/Sources/Pageboy/Utilities/Extensions/UIScrollView+Interaction.swift
similarity index 67%
rename from Sources/Pageboy/Utilities/Extensions/UIScrollView+ScrollActivity.swift
rename to Sources/Pageboy/Utilities/Extensions/UIScrollView+Interaction.swift
index 2938a468..52c6e61e 100644
--- a/Sources/Pageboy/Utilities/Extensions/UIScrollView+ScrollActivity.swift
+++ b/Sources/Pageboy/Utilities/Extensions/UIScrollView+Interaction.swift
@@ -1,5 +1,5 @@
 //
-//  UIScrollView+ScrollActivity.swift
+//  UIScrollView+Interaction.swift
 //  Pageboy
 //
 //  Created by Merrick Sapsford on 23/01/2018.
@@ -14,4 +14,9 @@ internal extension UIScrollView {
     var isProbablyActiveInScroll: Bool {
         return isTracking || isDecelerating
     }
+    
+    func cancelTouches() {
+        panGestureRecognizer.isEnabled = false
+        panGestureRecognizer.isEnabled = true
+    }
 }