Skip to content

Commit 9466cc0

Browse files
committed
Introduce transition protocols to decouple custom transition code
- introduce swipe-to-go-back for WebController - refactor Expand and Dismiss animations to use NavigationAnimatable protocol
1 parent 98a1d31 commit 9466cc0

File tree

14 files changed

+274
-64
lines changed

14 files changed

+274
-64
lines changed

SakaiClientiOS.xcodeproj/project.pbxproj

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
512748C9210E600200A5A74E /* ResourceNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512748C8210E600200A5A74E /* ResourceNode.swift */; };
4343
5128310F21D03DF800DB8DA8 /* CheckBoxCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5128310E21D03DF800DB8DA8 /* CheckBoxCell.swift */; };
4444
5128311421D0847D00DB8DA8 /* ExpandPresentAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5128311321D0847D00DB8DA8 /* ExpandPresentAnimationController.swift */; };
45-
5128311621D14C3E00DB8DA8 /* AnimationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5128311521D14C3E00DB8DA8 /* AnimationHelper.swift */; };
4645
5128311B21D1607400DB8DA8 /* Animatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5128311A21D1607400DB8DA8 /* Animatable.swift */; };
4746
5128311D21D18B9600DB8DA8 /* CollapseDismissAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5128311C21D18B9600DB8DA8 /* CollapseDismissAnimationController.swift */; };
4847
5129956821CCDB1C00BED3E5 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5129956721CCDB1C00BED3E5 /* UIColorExtension.swift */; };
@@ -101,6 +100,10 @@
101100
518903BD210AAE1F00C551AE /* LoadableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518903BC210AAE1F00C551AE /* LoadableController.swift */; };
102101
518903C1210AB39500C551AE /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518903C0210AB39500C551AE /* UIViewControllerExtension.swift */; };
103102
518903C3210AC3B200C551AE /* ResourceItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518903C2210AC3B200C551AE /* ResourceItem.swift */; };
103+
518988D121E8633500F8E400 /* NavigationAnimatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518988D021E8633500F8E400 /* NavigationAnimatable.swift */; };
104+
518988D521E8673300F8E400 /* SystemPopAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518988D421E8673300F8E400 /* SystemPopAnimator.swift */; };
105+
518988D921E869C300F8E400 /* Interactable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518988D821E869C300F8E400 /* Interactable.swift */; };
106+
518988DC21E86DA500F8E400 /* LeftEdgeInteractionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518988DB21E86DA500F8E400 /* LeftEdgeInteractionController.swift */; };
104107
518AC341213756E000037087 /* SakaiError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518AC340213756E000037087 /* SakaiError.swift */; };
105108
518AC34E2137840300037087 /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518AC34D2137840300037087 /* LoadingIndicator.swift */; };
106109
518AC35021379DC100037087 /* NetworkSourceDelegateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518AC34F21379DC100037087 /* NetworkSourceDelegateExtension.swift */; };
@@ -229,7 +232,6 @@
229232
512748C8210E600200A5A74E /* ResourceNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceNode.swift; sourceTree = "<group>"; };
230233
5128310E21D03DF800DB8DA8 /* CheckBoxCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxCell.swift; sourceTree = "<group>"; };
231234
5128311321D0847D00DB8DA8 /* ExpandPresentAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandPresentAnimationController.swift; sourceTree = "<group>"; };
232-
5128311521D14C3E00DB8DA8 /* AnimationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationHelper.swift; sourceTree = "<group>"; };
233235
5128311A21D1607400DB8DA8 /* Animatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animatable.swift; sourceTree = "<group>"; };
234236
5128311C21D18B9600DB8DA8 /* CollapseDismissAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapseDismissAnimationController.swift; sourceTree = "<group>"; };
235237
5129956721CCDB1C00BED3E5 /* UIColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtension.swift; sourceTree = "<group>"; };
@@ -289,6 +291,10 @@
289291
518903BC210AAE1F00C551AE /* LoadableController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableController.swift; sourceTree = "<group>"; };
290292
518903C0210AB39500C551AE /* UIViewControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtension.swift; sourceTree = "<group>"; };
291293
518903C2210AC3B200C551AE /* ResourceItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceItem.swift; sourceTree = "<group>"; };
294+
518988D021E8633500F8E400 /* NavigationAnimatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationAnimatable.swift; sourceTree = "<group>"; };
295+
518988D421E8673300F8E400 /* SystemPopAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemPopAnimator.swift; sourceTree = "<group>"; };
296+
518988D821E869C300F8E400 /* Interactable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interactable.swift; sourceTree = "<group>"; };
297+
518988DB21E86DA500F8E400 /* LeftEdgeInteractionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftEdgeInteractionController.swift; sourceTree = "<group>"; };
292298
518AC340213756E000037087 /* SakaiError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SakaiError.swift; sourceTree = "<group>"; };
293299
518AC34D2137840300037087 /* LoadingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = "<group>"; };
294300
518AC34F21379DC100037087 /* NetworkSourceDelegateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkSourceDelegateExtension.swift; sourceTree = "<group>"; };
@@ -477,8 +483,9 @@
477483
5128311721D15C5E00DB8DA8 /* Animation */ = {
478484
isa = PBXGroup;
479485
children = (
480-
5128311521D14C3E00DB8DA8 /* AnimationHelper.swift */,
481486
5128311A21D1607400DB8DA8 /* Animatable.swift */,
487+
518988D021E8633500F8E400 /* NavigationAnimatable.swift */,
488+
518988D821E869C300F8E400 /* Interactable.swift */,
482489
);
483490
path = Animation;
484491
sourceTree = "<group>";
@@ -600,6 +607,7 @@
600607
51835041211E9A49008F2CF2 /* Web */ = {
601608
isa = PBXGroup;
602609
children = (
610+
518988DA21E86D8E00F8E400 /* WebTransition */,
603611
511114AB20D6CD440077F872 /* WebController.swift */,
604612
51835042211E9A75008F2CF2 /* WebNavigationController.swift */,
605613
5197E6BC2134317F0019DCC9 /* TextViewDelegateExtension.swift */,
@@ -619,6 +627,15 @@
619627
path = ControllerBehavior;
620628
sourceTree = "<group>";
621629
};
630+
518988DA21E86D8E00F8E400 /* WebTransition */ = {
631+
isa = PBXGroup;
632+
children = (
633+
518988DB21E86DA500F8E400 /* LeftEdgeInteractionController.swift */,
634+
518988D421E8673300F8E400 /* SystemPopAnimator.swift */,
635+
);
636+
path = WebTransition;
637+
sourceTree = "<group>";
638+
};
622639
518CFCAA20B4E64500D5AE8F /* SitePages */ = {
623640
isa = PBXGroup;
624641
children = (
@@ -1083,11 +1100,14 @@
10831100
518903B221092E5600C551AE /* SakaiService.swift in Sources */,
10841101
5197E6BB213396DD0019DCC9 /* ChatRoomController.swift in Sources */,
10851102
518CFCAC20B4E68200D5AE8F /* SiteGradebookController.swift in Sources */,
1103+
518988DC21E86DA500F8E400 /* LeftEdgeInteractionController.swift in Sources */,
10861104
5197E6CB2134E8D80019DCC9 /* ChatTextView.swift in Sources */,
10871105
51C9791920F83D3300191DD6 /* GradebookDataFetcher.swift in Sources */,
10881106
5113C133209286D9001929DA /* GradebookController.swift in Sources */,
10891107
51C9791520F81A3E00191DD6 /* GradebookDataProvider.swift in Sources */,
10901108
51EBE83321E5461F00E95300 /* SakaiHTTPMethod.swift in Sources */,
1109+
518988D521E8673300F8E400 /* SystemPopAnimator.swift in Sources */,
1110+
518988D921E869C300F8E400 /* Interactable.swift in Sources */,
10911111
51A472E020F9C15700CC95F0 /* AssignmentDataFetcher.swift in Sources */,
10921112
515915452169C55900D3730E /* ReloadActions.swift in Sources */,
10931113
51DEE54020FEFB41008E709D /* SiteTableManager.swift in Sources */,
@@ -1100,7 +1120,6 @@
11001120
51A472DC20F9C13000CC95F0 /* AssignmentTableDataProvider.swift in Sources */,
11011121
513E5A7E21E163C3007BFD9A /* CreditsController.swift in Sources */,
11021122
518903BD210AAE1F00C551AE /* LoadableController.swift in Sources */,
1103-
5128311621D14C3E00DB8DA8 /* AnimationHelper.swift in Sources */,
11041123
517B614C21D8CED800BF5BD8 /* AnnouncementElement.swift in Sources */,
11051124
51D5EA1321504A2300D7B85C /* LoginWebViewController.swift in Sources */,
11061125
51C4B7F820A8CAC400DD6696 /* GradeItem.swift in Sources */,
@@ -1127,6 +1146,7 @@
11271146
DE0599F91DFD93B200D19D17 /* AppDelegate.swift in Sources */,
11281147
511114BD20DDF8DF0077F872 /* AssignmentPageView.swift in Sources */,
11291148
51C4B7FA20A9247C00DD6696 /* DefaultController.swift in Sources */,
1149+
518988D121E8633500F8E400 /* NavigationAnimatable.swift in Sources */,
11301150
51DEE53020FC250A008E709D /* AnnouncementDataProvider.swift in Sources */,
11311151
51DEE551210041A5008E709D /* SiteGradebookDataFetcher.swift in Sources */,
11321152
51C4B7F420A8BBF800DD6696 /* GradebookCell.swift in Sources */,

SakaiClientiOS/Controllers/Animation/AnimationHelper.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Interactable.swift
3+
// SakaiClientiOS
4+
//
5+
// Created by Pranay Neelagiri on 1/11/19.
6+
//
7+
8+
import UIKit
9+
10+
protocol Interactable {
11+
var interactionController: UIPercentDrivenInteractiveTransition? { get }
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// NavigationAnimatable.swift
3+
// SakaiClientiOS
4+
//
5+
// Created by Pranay Neelagiri on 1/11/19.
6+
//
7+
8+
import Foundation
9+
import UIKit
10+
11+
protocol NavigationAnimatable {
12+
func animationControllerForPop(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning?
13+
func animationControllerForPush(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning?
14+
}

SakaiClientiOS/Controllers/Assignment/AssignmentController.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class AssignmentController: UITableViewController {
1919

2020
override func viewDidLoad() {
2121
super.viewDidLoad()
22-
navigationController?.delegate = self
2322
assignmentsTableManager.selectedAt.delegate(to: self) { (self, indexPath) -> Void in
2423
self.assignmentsTableManager.toggleSite(at: indexPath)
2524
}
@@ -114,14 +113,15 @@ extension AssignmentController: Animatable {
114113
}
115114
}
116115

117-
extension AssignmentController: UINavigationControllerDelegate {
118-
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
119-
if fromVC is AssignmentController && toVC is PagesController {
116+
extension AssignmentController: NavigationAnimatable {
117+
func animationControllerForPop(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
118+
return nil
119+
}
120+
121+
func animationControllerForPush(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
122+
if controller is PagesController {
120123
return ExpandPresentAnimationController(resizingDuration: 0.5)
121-
} else if toVC is AssignmentController && fromVC is PagesController {
122-
return CollapseDismissAnimationController(resizingDuration: 0.5)
123-
} else {
124-
return nil
125124
}
125+
return nil
126126
}
127127
}

SakaiClientiOS/Controllers/Assignment/PagesController.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,16 @@ extension PagesController: Animatable {
257257
childView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
258258
}
259259
}
260+
261+
extension PagesController: NavigationAnimatable {
262+
func animationControllerForPop(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
263+
if controller is AssignmentController || controller is SiteAssignmentController {
264+
return CollapseDismissAnimationController(resizingDuration: 0.5)
265+
}
266+
return nil
267+
}
268+
269+
func animationControllerForPush(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
270+
return nil
271+
}
272+
}

SakaiClientiOS/Controllers/Gradebook/GradebookTableManager.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ class GradebookTableManager:
8585
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
8686
var direction: Direction = .up
8787

88-
if scrollView.contentOffset.y > lastContentOffset {
89-
direction = .down
88+
if scrollView.contentOffset.y == lastContentOffset {
89+
hideHeaderCell()
90+
return
9091
}
9192
lastContentOffset = scrollView.contentOffset.y
9293

SakaiClientiOS/Controllers/Home/HomeController.swift

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ class HomeController: UITableViewController {
2222
super.viewDidLoad()
2323

2424
title = "Classes"
25-
navigationController?.delegate = self
26-
navigationController?.interactivePopGestureRecognizer?.delegate = nil
2725

2826
// Ensure the rest of the app is locked until the source of truth
2927
// is loaded
@@ -173,22 +171,3 @@ extension HomeController: NetworkSourceDelegate {
173171
.post(name: Notification.Name(rawValue: ReloadActions.reload.rawValue), object: nil)
174172
}
175173
}
176-
177-
// MARK: UINavigationControllerDelegate Extension
178-
179-
extension HomeController: UINavigationControllerDelegate {
180-
func navigationController (_ navigationController: UINavigationController,
181-
animationControllerFor operation: UINavigationControllerOperation,
182-
from fromVC: UIViewController,
183-
to toVC: UIViewController)
184-
-> UIViewControllerAnimatedTransitioning? {
185-
186-
if fromVC is SiteAssignmentController && operation == .push {
187-
return ExpandPresentAnimationController(resizingDuration: 0.5)
188-
} else if toVC is SiteAssignmentController && operation == .pop {
189-
return CollapseDismissAnimationController(resizingDuration: 0.5)
190-
} else {
191-
return nil
192-
}
193-
}
194-
}

SakaiClientiOS/Controllers/Home/SitePages/SiteAssignmentController.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,16 @@ extension SiteAssignmentController: Animatable {
9696
return siteAssignmentCollectionManager.selectedCellFrame
9797
}
9898
}
99+
100+
extension SiteAssignmentController: NavigationAnimatable {
101+
func animationControllerForPop(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
102+
return nil
103+
}
104+
105+
func animationControllerForPush(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
106+
if controller is PagesController {
107+
return ExpandPresentAnimationController(resizingDuration: 0.5)
108+
}
109+
return nil
110+
}
111+
}

SakaiClientiOS/Controllers/NavigationController.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,41 @@ class NavigationController: UINavigationController {
2121
toolbar.tintColor = Palette.main.toolBarColor
2222
toolbar.barStyle = Palette.main.barStyle
2323
toolbar.barTintColor = Palette.main.tabBarBackgroundColor
24+
25+
interactivePopGestureRecognizer?.delegate = self
26+
delegate = self
27+
}
28+
}
29+
30+
extension NavigationController: UINavigationControllerDelegate {
31+
func navigationController(_ navigationController: UINavigationController,
32+
animationControllerFor operation: UINavigationControllerOperation,
33+
from fromVC: UIViewController,
34+
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
35+
if let origin = fromVC as? NavigationAnimatable {
36+
switch operation {
37+
case .none:
38+
return nil
39+
case .push:
40+
return origin.animationControllerForPush(to: toVC)
41+
case .pop:
42+
return origin.animationControllerForPop(to: toVC)
43+
}
44+
}
45+
return nil
46+
}
47+
48+
func navigationController(_ navigationController: UINavigationController,
49+
interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
50+
if let interactable = animationController as? Interactable {
51+
return interactable.interactionController
52+
}
53+
return nil
54+
}
55+
}
56+
57+
extension NavigationController: UIGestureRecognizerDelegate {
58+
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
59+
return viewControllers.count > 1
2460
}
2561
}

SakaiClientiOS/Controllers/Web/WebController.swift

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import SafariServices
1818
class WebController: UIViewController {
1919

2020
private var webView: WKWebView!
21+
private var edgeInteractionController: LeftEdgeInteractionController!
2122

2223
private let progressView: UIProgressView = {
2324
let progressView = UIProgressView(progressViewStyle: .default)
@@ -77,7 +78,7 @@ class WebController: UIViewController {
7778
}
7879

7980
/// Manage dismissing action for webView
80-
lazy var dismissWebView: (() -> Void) = { [weak self] in
81+
@objc lazy var dismissWebView: (() -> Void) = { [weak self] in
8182
self?.navigationController?.popViewController(animated: true)
8283
}
8384

@@ -115,11 +116,7 @@ class WebController: UIViewController {
115116
webView.constrainToEdges(of: view)
116117
}
117118

118-
// Normal pop recognizer is buggy with WKWebView
119-
let swipeRight = UISwipeGestureRecognizer(target: self,
120-
action: #selector(self?.dismissWebController))
121-
swipeRight.direction = .right
122-
webView.addGestureRecognizer(swipeRight)
119+
self?.edgeInteractionController = LeftEdgeInteractionController(view: webView, in: self)
123120

124121
if let target = self {
125122
webView.addObserver(target,
@@ -156,13 +153,19 @@ class WebController: UIViewController {
156153
if shouldLoad && didInitialize {
157154
loadURL(urlOpt: url)
158155
}
156+
if webView != nil {
157+
webView.scrollView.isScrollEnabled = true
158+
}
159159
navigationController?.navigationBar.tintColor = Palette.main.toolBarColor
160160
navigationController?.setToolbarHidden(false, animated: true)
161161
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
162162
}
163163

164164
override func viewWillDisappear(_ animated: Bool) {
165165
super.viewWillDisappear(animated)
166+
if webView != nil {
167+
webView.scrollView.isScrollEnabled = false
168+
}
166169
if isMovingFromParentViewController {
167170
UIDevice.current
168171
.setValue(Int(UIInterfaceOrientation.portrait.rawValue),
@@ -252,9 +255,6 @@ extension WebController: WKUIDelegate, WKNavigationDelegate {
252255
openInSafari(url)
253256
return
254257
}
255-
if url.absoluteString != self.url?.absoluteString {
256-
shouldLoad = true
257-
}
258258
decisionHandler(.allow)
259259
}
260260

@@ -389,6 +389,7 @@ extension WebController {
389389
}
390390

391391
@objc func loadWebview() {
392+
shouldLoad = true
392393
loadURL(urlOpt: url)
393394
}
394395

@@ -402,3 +403,16 @@ extension WebController {
402403
}
403404

404405
extension WebController: Rotatable {}
406+
407+
extension WebController: NavigationAnimatable {
408+
func animationControllerForPop(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
409+
if edgeInteractionController.edge?.state == .began {
410+
return SystemPopAnimator(duration: 0.5, interactionController: edgeInteractionController)
411+
}
412+
return nil
413+
}
414+
415+
func animationControllerForPush(to controller: UIViewController) -> UIViewControllerAnimatedTransitioning? {
416+
return nil
417+
}
418+
}

0 commit comments

Comments
 (0)