├── .gitignore
├── Gagat Example
├── AppDelegate.swift
├── ArchiveTableCellView.swift
├── ArchiveTableViewController.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── appodden.imageset
│ │ ├── Contents.json
│ │ └── appodden.png
│ ├── ifiwereyou.imageset
│ │ ├── Contents.json
│ │ └── ifiwereyou.jpg
│ ├── loveandradio.imageset
│ │ ├── Contents.json
│ │ └── loveandradio.jpg
│ ├── nancy.imageset
│ │ ├── Contents.json
│ │ └── nancy.png
│ └── radiolab.imageset
│ │ ├── Contents.json
│ │ └── radiolab.jpg
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
└── StyleableNavigationController.swift
├── Gagat.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── Gagat.xcscheme
├── Gagat
├── AnimationUtilities.swift
├── Gagat.h
├── Gagat.swift
├── Info.plist
├── PessimisticPanGestureRecognizer.swift
└── TransitionCoordinator.swift
├── GagatObjectiveC Example
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Info.plist
├── StyleableNavigationController.h
├── StyleableNavigationController.m
├── StyleableViewController.h
├── StyleableViewController.m
└── main.m
├── GagatObjectiveC
├── Gagat.swift
├── GagatObjectiveC.h
└── Info.plist
├── LICENSE
├── README.md
├── gagat_example.gif
└── gagat_logo.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Generic
2 | .DS_Store
3 | ._*
4 | __*
5 | *.gz
6 | *.tar
7 | *.tgz
8 | tmp*
9 | tmp/*
10 | tmp/**/*
11 |
12 | # XCode
13 | build/*
14 | *.pbxuser
15 | *.mode?v3
16 | *.perspectivev3
17 | xcuserdata
18 | *.moved-aside
19 | *.xccheckout
20 |
21 | # Temp nibs and swap files
22 | *~.nib
23 | *.swp
24 | *~
25 |
26 | # Carthage
27 | Carthage
28 | *.framework.zip
29 |
--------------------------------------------------------------------------------
/Gagat Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-02-17.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Gagat
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 | private var transitionHandle: Gagat.TransitionHandle!
17 |
18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
19 | // Configure Gagat for the applications only window using a jelly factor that is
20 | // slightly larger than the default factor of 1.0. We'll use the root view controller
21 | // as the styleable object, but you can use any object that conforms to `GagatStyleable`.
22 | //
23 | // Note: Make sure you keep a reference to the value returned from `Gagat.configure(for:using:)`.
24 | // If this object is deallocated then the Gagat transition will no longer work.
25 | let configuration = Gagat.Configuration(jellyFactor: 1.5)
26 | let styleableNavigationController = window!.rootViewController as! StyleableNavigationController
27 | transitionHandle = Gagat.configure(for: window!, with: styleableNavigationController, using: configuration)
28 |
29 | return true
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Gagat Example/ArchiveTableCellView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ArchiveTableCellView.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-06-03.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ArchiveTableCellView: UITableViewCell {
12 |
13 | struct Style {
14 | let backgroundColor: UIColor
15 | let titleTextColor: UIColor
16 | let descriptionTextColor: UIColor
17 |
18 | static let light = Style(
19 | backgroundColor: .white,
20 | titleTextColor: .black,
21 | descriptionTextColor: UIColor(white: 0.4, alpha: 1.0)
22 | )
23 |
24 | static let dark = Style(
25 | backgroundColor: UIColor(white: 0.2, alpha: 1.0),
26 | titleTextColor: .white,
27 | descriptionTextColor: UIColor(white: 0.6, alpha: 1.0)
28 | )
29 | }
30 |
31 | @IBOutlet private weak var titleLabel: UILabel!
32 | @IBOutlet private weak var artworkImageView: UIImageView!
33 | @IBOutlet private weak var descriptionLabel: UILabel!
34 |
35 | override func awakeFromNib() {
36 | super.awakeFromNib()
37 | artworkImageView.layer.cornerRadius = 10.0
38 | }
39 |
40 | func apply(style: Style) {
41 | backgroundColor = style.backgroundColor
42 | titleLabel.textColor = style.titleTextColor
43 | descriptionLabel.textColor = style.descriptionTextColor
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Gagat Example/ArchiveTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ArchiveTableViewController.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-06-03.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Gagat
11 |
12 | class ArchiveTableViewController: UITableViewController, UIGestureRecognizerDelegate {
13 |
14 | // MARK: - UIViewController methods
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | apply(currentStyle)
19 | }
20 |
21 | // MARK: - UITableViewDelegate methods
22 |
23 | override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
24 | guard let archiveCell = cell as? ArchiveTableCellView else {
25 | return
26 | }
27 |
28 | archiveCell.apply(style: currentStyle.cellStyle)
29 | }
30 |
31 | // MARK: - Applying styles
32 |
33 | private struct Style {
34 | let backgroundColor: UIColor
35 | let separatorColor: UIColor?
36 | let cellStyle: ArchiveTableCellView.Style
37 |
38 | static let dark = Style(
39 | backgroundColor: UIColor(white: 0.15, alpha: 1.0),
40 | separatorColor: UIColor(white: 0.35, alpha: 1.0),
41 | cellStyle: .dark
42 | )
43 |
44 | static let light = Style(
45 | backgroundColor: .groupTableViewBackground,
46 | separatorColor: UIColor(white: 0.81, alpha: 1.0),
47 | cellStyle: .light
48 | )
49 | }
50 |
51 | private var currentStyle: Style {
52 | return useDarkMode ? .dark : .light
53 | }
54 |
55 | fileprivate var useDarkMode = false {
56 | didSet { apply(currentStyle) }
57 | }
58 |
59 | private func apply(_ style: Style) {
60 | tableView.backgroundColor = style.backgroundColor
61 | tableView.separatorColor = style.separatorColor
62 | apply(style.cellStyle, toCells: tableView.visibleCells)
63 | }
64 |
65 | private func apply(_ cellStyle: ArchiveTableCellView.Style, toCells cells: [UITableViewCell]) {
66 | for cell in cells {
67 | guard let archiveCell = cell as? ArchiveTableCellView else {
68 | continue
69 | }
70 |
71 | archiveCell.apply(style: cellStyle)
72 | }
73 | }
74 |
75 | }
76 |
77 |
78 | extension ArchiveTableViewController: GagatStyleable {
79 |
80 | func toggleActiveStyle() {
81 | useDarkMode = !useDarkMode
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/appodden.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "appodden.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/appodden.imageset/appodden.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/Gagat Example/Assets.xcassets/appodden.imageset/appodden.png
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/ifiwereyou.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ifiwereyou.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/ifiwereyou.imageset/ifiwereyou.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/Gagat Example/Assets.xcassets/ifiwereyou.imageset/ifiwereyou.jpg
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/loveandradio.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "loveandradio.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/loveandradio.imageset/loveandradio.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/Gagat Example/Assets.xcassets/loveandradio.imageset/loveandradio.jpg
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/nancy.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "nancy.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/nancy.imageset/nancy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/Gagat Example/Assets.xcassets/nancy.imageset/nancy.png
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/radiolab.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "radiolab.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Gagat Example/Assets.xcassets/radiolab.imageset/radiolab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/Gagat Example/Assets.xcassets/radiolab.imageset/radiolab.jpg
--------------------------------------------------------------------------------
/Gagat Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Gagat Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
--------------------------------------------------------------------------------
/Gagat Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Gagat Example/StyleableNavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StyleableNavigationController.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-06-03.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Gagat
11 |
12 | class StyleableNavigationController: UINavigationController {
13 |
14 | fileprivate var useDarkMode = false {
15 | didSet {
16 | navigationBar.barStyle = useDarkMode ? .black : .default
17 | }
18 | }
19 | }
20 |
21 | extension StyleableNavigationController: GagatStyleable {
22 |
23 | func styleTransitionWillBegin() {
24 | // Do any work you might need to do before the transition snapshot is taken.
25 | if let styleableChildViewController = topViewController as? GagatStyleable {
26 | styleableChildViewController.styleTransitionWillBegin()
27 | }
28 | }
29 |
30 | func styleTransitionDidEnd() {
31 | // Do any work you might need to do once the transition has completed.
32 | if let styleableChildViewController = topViewController as? GagatStyleable {
33 | styleableChildViewController.styleTransitionDidEnd()
34 | }
35 | }
36 |
37 | func toggleActiveStyle() {
38 | useDarkMode = !useDarkMode
39 |
40 | // It's up to us to get any child view controllers to
41 | // toggle their active style. In this example application we've made
42 | // the child view controller also conform to `GagatStyleable`, but
43 | // this is not required by Gagat.
44 | if let styleableChildViewController = topViewController as? GagatStyleable {
45 | styleableChildViewController.toggleActiveStyle()
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Gagat.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9355030F1EF2F4CA00FD428F /* GagatObjectiveC.h in Headers */ = {isa = PBXBuildFile; fileRef = 9355030D1EF2F4CA00FD428F /* GagatObjectiveC.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 935503141EF2F4E900FD428F /* Gagat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935503131EF2F4E900FD428F /* Gagat.swift */; };
12 | 935503171EF2F4F800FD428F /* Gagat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9390063E1EE2038900BF6787 /* Gagat.framework */; };
13 | 9390062D1EE2024700BF6787 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 939006211EE2024700BF6787 /* AppDelegate.swift */; };
14 | 9390062E1EE2024700BF6787 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 939006221EE2024700BF6787 /* Assets.xcassets */; };
15 | 939006361EE2029E00BF6787 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 939006231EE2024700BF6787 /* LaunchScreen.storyboard */; };
16 | 939006371EE2029E00BF6787 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 939006251EE2024700BF6787 /* Main.storyboard */; };
17 | 939006421EE2038900BF6787 /* Gagat.h in Headers */ = {isa = PBXBuildFile; fileRef = 939006401EE2038900BF6787 /* Gagat.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | 939006451EE2038900BF6787 /* Gagat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9390063E1EE2038900BF6787 /* Gagat.framework */; };
19 | 939006471EE2038900BF6787 /* Gagat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9390063E1EE2038900BF6787 /* Gagat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
20 | 9390064F1EE203BF00BF6787 /* AnimationUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9390064B1EE203BF00BF6787 /* AnimationUtilities.swift */; };
21 | 939006501EE203BF00BF6787 /* Gagat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9390064C1EE203BF00BF6787 /* Gagat.swift */; };
22 | 939006511EE203BF00BF6787 /* PessimisticPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9390064D1EE203BF00BF6787 /* PessimisticPanGestureRecognizer.swift */; };
23 | 939006521EE203BF00BF6787 /* TransitionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9390064E1EE203BF00BF6787 /* TransitionCoordinator.swift */; };
24 | 939006A51EE2B15D00BF6787 /* ArchiveTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 939006A41EE2B15D00BF6787 /* ArchiveTableViewController.swift */; };
25 | 939006A71EE2B17800BF6787 /* ArchiveTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 939006A61EE2B17800BF6787 /* ArchiveTableCellView.swift */; };
26 | 939006A91EE2B36100BF6787 /* StyleableNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 939006A81EE2B36100BF6787 /* StyleableNavigationController.swift */; };
27 | A5C93695217C82D100776DFC /* StyleableNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5C9368B217C82D100776DFC /* StyleableNavigationController.m */; };
28 | A5C93697217C82D100776DFC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5C9368D217C82D100776DFC /* Assets.xcassets */; };
29 | A5C93698217C82D100776DFC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A5C9368E217C82D100776DFC /* LaunchScreen.storyboard */; };
30 | A5C9369A217C82D100776DFC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A5C93692217C82D100776DFC /* AppDelegate.m */; };
31 | A5C9369D217C83DE00776DFC /* GagatObjectiveC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9355030B1EF2F4CA00FD428F /* GagatObjectiveC.framework */; };
32 | A5C9369E217C83DE00776DFC /* GagatObjectiveC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9355030B1EF2F4CA00FD428F /* GagatObjectiveC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
33 | A5C936C6217C84C500776DFC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A5C936C5217C84C500776DFC /* main.m */; };
34 | A5C936CC217C8EC800776DFC /* StyleableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5C936CB217C8EC800776DFC /* StyleableViewController.m */; };
35 | A5C936CE217C924A00776DFC /* Gagat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9390063E1EE2038900BF6787 /* Gagat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
36 | /* End PBXBuildFile section */
37 |
38 | /* Begin PBXContainerItemProxy section */
39 | 935503151EF2F4F300FD428F /* PBXContainerItemProxy */ = {
40 | isa = PBXContainerItemProxy;
41 | containerPortal = 9386EDD21E577236009079B6 /* Project object */;
42 | proxyType = 1;
43 | remoteGlobalIDString = 9390063D1EE2038900BF6787;
44 | remoteInfo = Gagat;
45 | };
46 | 939006431EE2038900BF6787 /* PBXContainerItemProxy */ = {
47 | isa = PBXContainerItemProxy;
48 | containerPortal = 9386EDD21E577236009079B6 /* Project object */;
49 | proxyType = 1;
50 | remoteGlobalIDString = 9390063D1EE2038900BF6787;
51 | remoteInfo = Gagat;
52 | };
53 | A5C9369F217C83DE00776DFC /* PBXContainerItemProxy */ = {
54 | isa = PBXContainerItemProxy;
55 | containerPortal = 9386EDD21E577236009079B6 /* Project object */;
56 | proxyType = 1;
57 | remoteGlobalIDString = 9355030A1EF2F4CA00FD428F;
58 | remoteInfo = GagatObjectiveC;
59 | };
60 | A5C936CF217C924A00776DFC /* PBXContainerItemProxy */ = {
61 | isa = PBXContainerItemProxy;
62 | containerPortal = 9386EDD21E577236009079B6 /* Project object */;
63 | proxyType = 1;
64 | remoteGlobalIDString = 9390063D1EE2038900BF6787;
65 | remoteInfo = Gagat;
66 | };
67 | /* End PBXContainerItemProxy section */
68 |
69 | /* Begin PBXCopyFilesBuildPhase section */
70 | 939006461EE2038900BF6787 /* Embed Frameworks */ = {
71 | isa = PBXCopyFilesBuildPhase;
72 | buildActionMask = 2147483647;
73 | dstPath = "";
74 | dstSubfolderSpec = 10;
75 | files = (
76 | 939006471EE2038900BF6787 /* Gagat.framework in Embed Frameworks */,
77 | );
78 | name = "Embed Frameworks";
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | A5C936A1217C83DE00776DFC /* Embed Frameworks */ = {
82 | isa = PBXCopyFilesBuildPhase;
83 | buildActionMask = 2147483647;
84 | dstPath = "";
85 | dstSubfolderSpec = 10;
86 | files = (
87 | A5C9369E217C83DE00776DFC /* GagatObjectiveC.framework in Embed Frameworks */,
88 | A5C936CE217C924A00776DFC /* Gagat.framework in Embed Frameworks */,
89 | );
90 | name = "Embed Frameworks";
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | /* End PBXCopyFilesBuildPhase section */
94 |
95 | /* Begin PBXFileReference section */
96 | 9355030B1EF2F4CA00FD428F /* GagatObjectiveC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GagatObjectiveC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
97 | 9355030D1EF2F4CA00FD428F /* GagatObjectiveC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GagatObjectiveC.h; sourceTree = ""; };
98 | 9355030E1EF2F4CA00FD428F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
99 | 935503131EF2F4E900FD428F /* Gagat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gagat.swift; sourceTree = ""; };
100 | 9386EDDA1E577236009079B6 /* Gagat Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Gagat Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
101 | 939006211EE2024700BF6787 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
102 | 939006221EE2024700BF6787 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
103 | 939006241EE2024700BF6787 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
104 | 939006261EE2024700BF6787 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
105 | 939006281EE2024700BF6787 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
106 | 9390063E1EE2038900BF6787 /* Gagat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Gagat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
107 | 939006401EE2038900BF6787 /* Gagat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Gagat.h; sourceTree = ""; };
108 | 939006411EE2038900BF6787 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
109 | 9390064B1EE203BF00BF6787 /* AnimationUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationUtilities.swift; sourceTree = ""; };
110 | 9390064C1EE203BF00BF6787 /* Gagat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gagat.swift; sourceTree = ""; };
111 | 9390064D1EE203BF00BF6787 /* PessimisticPanGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PessimisticPanGestureRecognizer.swift; sourceTree = ""; };
112 | 9390064E1EE203BF00BF6787 /* TransitionCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionCoordinator.swift; sourceTree = ""; };
113 | 939006A41EE2B15D00BF6787 /* ArchiveTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArchiveTableViewController.swift; sourceTree = ""; };
114 | 939006A61EE2B17800BF6787 /* ArchiveTableCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArchiveTableCellView.swift; sourceTree = ""; };
115 | 939006A81EE2B36100BF6787 /* StyleableNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StyleableNavigationController.swift; sourceTree = ""; };
116 | A5C93685217C826A00776DFC /* GagatObjectiveC Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "GagatObjectiveC Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
117 | A5C9368B217C82D100776DFC /* StyleableNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleableNavigationController.m; sourceTree = ""; };
118 | A5C9368D217C82D100776DFC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
119 | A5C9368F217C82D100776DFC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
120 | A5C93692217C82D100776DFC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
121 | A5C93693217C82D100776DFC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
122 | A5C936C4217C847200776DFC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
123 | A5C936C5217C84C500776DFC /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
124 | A5C936C9217C8A1B00776DFC /* StyleableNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StyleableNavigationController.h; sourceTree = ""; };
125 | A5C936CA217C8EC800776DFC /* StyleableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StyleableViewController.h; sourceTree = ""; };
126 | A5C936CB217C8EC800776DFC /* StyleableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StyleableViewController.m; sourceTree = ""; };
127 | /* End PBXFileReference section */
128 |
129 | /* Begin PBXFrameworksBuildPhase section */
130 | 935503071EF2F4CA00FD428F /* Frameworks */ = {
131 | isa = PBXFrameworksBuildPhase;
132 | buildActionMask = 2147483647;
133 | files = (
134 | 935503171EF2F4F800FD428F /* Gagat.framework in Frameworks */,
135 | );
136 | runOnlyForDeploymentPostprocessing = 0;
137 | };
138 | 9386EDD71E577236009079B6 /* Frameworks */ = {
139 | isa = PBXFrameworksBuildPhase;
140 | buildActionMask = 2147483647;
141 | files = (
142 | 939006451EE2038900BF6787 /* Gagat.framework in Frameworks */,
143 | );
144 | runOnlyForDeploymentPostprocessing = 0;
145 | };
146 | 9390063A1EE2038900BF6787 /* Frameworks */ = {
147 | isa = PBXFrameworksBuildPhase;
148 | buildActionMask = 2147483647;
149 | files = (
150 | );
151 | runOnlyForDeploymentPostprocessing = 0;
152 | };
153 | A5C9367A217C826A00776DFC /* Frameworks */ = {
154 | isa = PBXFrameworksBuildPhase;
155 | buildActionMask = 2147483647;
156 | files = (
157 | A5C9369D217C83DE00776DFC /* GagatObjectiveC.framework in Frameworks */,
158 | );
159 | runOnlyForDeploymentPostprocessing = 0;
160 | };
161 | /* End PBXFrameworksBuildPhase section */
162 |
163 | /* Begin PBXGroup section */
164 | 9355030C1EF2F4CA00FD428F /* GagatObjectiveC */ = {
165 | isa = PBXGroup;
166 | children = (
167 | 935503131EF2F4E900FD428F /* Gagat.swift */,
168 | 9355030D1EF2F4CA00FD428F /* GagatObjectiveC.h */,
169 | 9355030E1EF2F4CA00FD428F /* Info.plist */,
170 | );
171 | path = GagatObjectiveC;
172 | sourceTree = "";
173 | };
174 | 9386EDD11E577236009079B6 = {
175 | isa = PBXGroup;
176 | children = (
177 | 9390061F1EE2024700BF6787 /* Gagat Example */,
178 | 9390063F1EE2038900BF6787 /* Gagat */,
179 | A5C93689217C82D100776DFC /* GagatObjectiveC Example */,
180 | 9355030C1EF2F4CA00FD428F /* GagatObjectiveC */,
181 | 9386EDDB1E577236009079B6 /* Products */,
182 | );
183 | sourceTree = "";
184 | usesTabs = 1;
185 | };
186 | 9386EDDB1E577236009079B6 /* Products */ = {
187 | isa = PBXGroup;
188 | children = (
189 | 9386EDDA1E577236009079B6 /* Gagat Example.app */,
190 | 9390063E1EE2038900BF6787 /* Gagat.framework */,
191 | 9355030B1EF2F4CA00FD428F /* GagatObjectiveC.framework */,
192 | A5C93685217C826A00776DFC /* GagatObjectiveC Example.app */,
193 | );
194 | name = Products;
195 | sourceTree = "";
196 | };
197 | 9390061F1EE2024700BF6787 /* Gagat Example */ = {
198 | isa = PBXGroup;
199 | children = (
200 | 939006211EE2024700BF6787 /* AppDelegate.swift */,
201 | 939006A41EE2B15D00BF6787 /* ArchiveTableViewController.swift */,
202 | 939006A61EE2B17800BF6787 /* ArchiveTableCellView.swift */,
203 | 939006A81EE2B36100BF6787 /* StyleableNavigationController.swift */,
204 | 939006251EE2024700BF6787 /* Main.storyboard */,
205 | 939006221EE2024700BF6787 /* Assets.xcassets */,
206 | 939006231EE2024700BF6787 /* LaunchScreen.storyboard */,
207 | 939006281EE2024700BF6787 /* Info.plist */,
208 | );
209 | path = "Gagat Example";
210 | sourceTree = "";
211 | };
212 | 9390063F1EE2038900BF6787 /* Gagat */ = {
213 | isa = PBXGroup;
214 | children = (
215 | 9390064B1EE203BF00BF6787 /* AnimationUtilities.swift */,
216 | 9390064C1EE203BF00BF6787 /* Gagat.swift */,
217 | 9390064D1EE203BF00BF6787 /* PessimisticPanGestureRecognizer.swift */,
218 | 9390064E1EE203BF00BF6787 /* TransitionCoordinator.swift */,
219 | 939006401EE2038900BF6787 /* Gagat.h */,
220 | 939006411EE2038900BF6787 /* Info.plist */,
221 | );
222 | path = Gagat;
223 | sourceTree = "";
224 | };
225 | A5C93689217C82D100776DFC /* GagatObjectiveC Example */ = {
226 | isa = PBXGroup;
227 | children = (
228 | A5C936C5217C84C500776DFC /* main.m */,
229 | A5C936C4217C847200776DFC /* AppDelegate.h */,
230 | A5C93692217C82D100776DFC /* AppDelegate.m */,
231 | A5C936C9217C8A1B00776DFC /* StyleableNavigationController.h */,
232 | A5C9368B217C82D100776DFC /* StyleableNavigationController.m */,
233 | A5C936CA217C8EC800776DFC /* StyleableViewController.h */,
234 | A5C936CB217C8EC800776DFC /* StyleableViewController.m */,
235 | A5C9368D217C82D100776DFC /* Assets.xcassets */,
236 | A5C9368E217C82D100776DFC /* LaunchScreen.storyboard */,
237 | A5C93693217C82D100776DFC /* Info.plist */,
238 | );
239 | path = "GagatObjectiveC Example";
240 | sourceTree = "";
241 | };
242 | /* End PBXGroup section */
243 |
244 | /* Begin PBXHeadersBuildPhase section */
245 | 935503081EF2F4CA00FD428F /* Headers */ = {
246 | isa = PBXHeadersBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 9355030F1EF2F4CA00FD428F /* GagatObjectiveC.h in Headers */,
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | 9390063B1EE2038900BF6787 /* Headers */ = {
254 | isa = PBXHeadersBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | 939006421EE2038900BF6787 /* Gagat.h in Headers */,
258 | );
259 | runOnlyForDeploymentPostprocessing = 0;
260 | };
261 | /* End PBXHeadersBuildPhase section */
262 |
263 | /* Begin PBXNativeTarget section */
264 | 9355030A1EF2F4CA00FD428F /* GagatObjectiveC */ = {
265 | isa = PBXNativeTarget;
266 | buildConfigurationList = 935503121EF2F4CA00FD428F /* Build configuration list for PBXNativeTarget "GagatObjectiveC" */;
267 | buildPhases = (
268 | 935503061EF2F4CA00FD428F /* Sources */,
269 | 935503071EF2F4CA00FD428F /* Frameworks */,
270 | 935503081EF2F4CA00FD428F /* Headers */,
271 | 935503091EF2F4CA00FD428F /* Resources */,
272 | );
273 | buildRules = (
274 | );
275 | dependencies = (
276 | 935503161EF2F4F300FD428F /* PBXTargetDependency */,
277 | );
278 | name = GagatObjectiveC;
279 | productName = GagatObjectiveC;
280 | productReference = 9355030B1EF2F4CA00FD428F /* GagatObjectiveC.framework */;
281 | productType = "com.apple.product-type.framework";
282 | };
283 | 9386EDD91E577236009079B6 /* Gagat Example */ = {
284 | isa = PBXNativeTarget;
285 | buildConfigurationList = 9386EDEC1E577236009079B6 /* Build configuration list for PBXNativeTarget "Gagat Example" */;
286 | buildPhases = (
287 | 9386EDD61E577236009079B6 /* Sources */,
288 | 9386EDD71E577236009079B6 /* Frameworks */,
289 | 9386EDD81E577236009079B6 /* Resources */,
290 | 939006461EE2038900BF6787 /* Embed Frameworks */,
291 | );
292 | buildRules = (
293 | );
294 | dependencies = (
295 | 939006441EE2038900BF6787 /* PBXTargetDependency */,
296 | );
297 | name = "Gagat Example";
298 | productName = Gagat;
299 | productReference = 9386EDDA1E577236009079B6 /* Gagat Example.app */;
300 | productType = "com.apple.product-type.application";
301 | };
302 | 9390063D1EE2038900BF6787 /* Gagat */ = {
303 | isa = PBXNativeTarget;
304 | buildConfigurationList = 939006481EE2038900BF6787 /* Build configuration list for PBXNativeTarget "Gagat" */;
305 | buildPhases = (
306 | 939006391EE2038900BF6787 /* Sources */,
307 | 9390063A1EE2038900BF6787 /* Frameworks */,
308 | 9390063B1EE2038900BF6787 /* Headers */,
309 | 9390063C1EE2038900BF6787 /* Resources */,
310 | );
311 | buildRules = (
312 | );
313 | dependencies = (
314 | );
315 | name = Gagat;
316 | productName = Gagat;
317 | productReference = 9390063E1EE2038900BF6787 /* Gagat.framework */;
318 | productType = "com.apple.product-type.framework";
319 | };
320 | A5C93672217C826A00776DFC /* GagatObjectiveC Example */ = {
321 | isa = PBXNativeTarget;
322 | buildConfigurationList = A5C93682217C826A00776DFC /* Build configuration list for PBXNativeTarget "GagatObjectiveC Example" */;
323 | buildPhases = (
324 | A5C93675217C826A00776DFC /* Sources */,
325 | A5C9367A217C826A00776DFC /* Frameworks */,
326 | A5C9367C217C826A00776DFC /* Resources */,
327 | A5C936A1217C83DE00776DFC /* Embed Frameworks */,
328 | );
329 | buildRules = (
330 | );
331 | dependencies = (
332 | A5C936A0217C83DE00776DFC /* PBXTargetDependency */,
333 | A5C936D0217C924A00776DFC /* PBXTargetDependency */,
334 | );
335 | name = "GagatObjectiveC Example";
336 | productName = Gagat;
337 | productReference = A5C93685217C826A00776DFC /* GagatObjectiveC Example.app */;
338 | productType = "com.apple.product-type.application";
339 | };
340 | /* End PBXNativeTarget section */
341 |
342 | /* Begin PBXProject section */
343 | 9386EDD21E577236009079B6 /* Project object */ = {
344 | isa = PBXProject;
345 | attributes = {
346 | LastSwiftUpdateCheck = 0820;
347 | LastUpgradeCheck = 0930;
348 | ORGANIZATIONNAME = "Cocoabeans Software";
349 | TargetAttributes = {
350 | 9355030A1EF2F4CA00FD428F = {
351 | CreatedOnToolsVersion = 8.3.2;
352 | LastSwiftMigration = 1000;
353 | ProvisioningStyle = Automatic;
354 | };
355 | 9386EDD91E577236009079B6 = {
356 | CreatedOnToolsVersion = 8.2;
357 | LastSwiftMigration = 1020;
358 | ProvisioningStyle = Automatic;
359 | };
360 | 9390063D1EE2038900BF6787 = {
361 | CreatedOnToolsVersion = 8.3.2;
362 | LastSwiftMigration = 1020;
363 | ProvisioningStyle = Automatic;
364 | };
365 | };
366 | };
367 | buildConfigurationList = 9386EDD51E577236009079B6 /* Build configuration list for PBXProject "Gagat" */;
368 | compatibilityVersion = "Xcode 3.2";
369 | developmentRegion = en;
370 | hasScannedForEncodings = 0;
371 | knownRegions = (
372 | en,
373 | Base,
374 | );
375 | mainGroup = 9386EDD11E577236009079B6;
376 | productRefGroup = 9386EDDB1E577236009079B6 /* Products */;
377 | projectDirPath = "";
378 | projectRoot = "";
379 | targets = (
380 | 9386EDD91E577236009079B6 /* Gagat Example */,
381 | 9390063D1EE2038900BF6787 /* Gagat */,
382 | A5C93672217C826A00776DFC /* GagatObjectiveC Example */,
383 | 9355030A1EF2F4CA00FD428F /* GagatObjectiveC */,
384 | );
385 | };
386 | /* End PBXProject section */
387 |
388 | /* Begin PBXResourcesBuildPhase section */
389 | 935503091EF2F4CA00FD428F /* Resources */ = {
390 | isa = PBXResourcesBuildPhase;
391 | buildActionMask = 2147483647;
392 | files = (
393 | );
394 | runOnlyForDeploymentPostprocessing = 0;
395 | };
396 | 9386EDD81E577236009079B6 /* Resources */ = {
397 | isa = PBXResourcesBuildPhase;
398 | buildActionMask = 2147483647;
399 | files = (
400 | 939006361EE2029E00BF6787 /* LaunchScreen.storyboard in Resources */,
401 | 939006371EE2029E00BF6787 /* Main.storyboard in Resources */,
402 | 9390062E1EE2024700BF6787 /* Assets.xcassets in Resources */,
403 | );
404 | runOnlyForDeploymentPostprocessing = 0;
405 | };
406 | 9390063C1EE2038900BF6787 /* Resources */ = {
407 | isa = PBXResourcesBuildPhase;
408 | buildActionMask = 2147483647;
409 | files = (
410 | );
411 | runOnlyForDeploymentPostprocessing = 0;
412 | };
413 | A5C9367C217C826A00776DFC /* Resources */ = {
414 | isa = PBXResourcesBuildPhase;
415 | buildActionMask = 2147483647;
416 | files = (
417 | A5C93697217C82D100776DFC /* Assets.xcassets in Resources */,
418 | A5C93698217C82D100776DFC /* LaunchScreen.storyboard in Resources */,
419 | );
420 | runOnlyForDeploymentPostprocessing = 0;
421 | };
422 | /* End PBXResourcesBuildPhase section */
423 |
424 | /* Begin PBXSourcesBuildPhase section */
425 | 935503061EF2F4CA00FD428F /* Sources */ = {
426 | isa = PBXSourcesBuildPhase;
427 | buildActionMask = 2147483647;
428 | files = (
429 | 935503141EF2F4E900FD428F /* Gagat.swift in Sources */,
430 | );
431 | runOnlyForDeploymentPostprocessing = 0;
432 | };
433 | 9386EDD61E577236009079B6 /* Sources */ = {
434 | isa = PBXSourcesBuildPhase;
435 | buildActionMask = 2147483647;
436 | files = (
437 | 939006A51EE2B15D00BF6787 /* ArchiveTableViewController.swift in Sources */,
438 | 939006A71EE2B17800BF6787 /* ArchiveTableCellView.swift in Sources */,
439 | 9390062D1EE2024700BF6787 /* AppDelegate.swift in Sources */,
440 | 939006A91EE2B36100BF6787 /* StyleableNavigationController.swift in Sources */,
441 | );
442 | runOnlyForDeploymentPostprocessing = 0;
443 | };
444 | 939006391EE2038900BF6787 /* Sources */ = {
445 | isa = PBXSourcesBuildPhase;
446 | buildActionMask = 2147483647;
447 | files = (
448 | 939006501EE203BF00BF6787 /* Gagat.swift in Sources */,
449 | 939006521EE203BF00BF6787 /* TransitionCoordinator.swift in Sources */,
450 | 939006511EE203BF00BF6787 /* PessimisticPanGestureRecognizer.swift in Sources */,
451 | 9390064F1EE203BF00BF6787 /* AnimationUtilities.swift in Sources */,
452 | );
453 | runOnlyForDeploymentPostprocessing = 0;
454 | };
455 | A5C93675217C826A00776DFC /* Sources */ = {
456 | isa = PBXSourcesBuildPhase;
457 | buildActionMask = 2147483647;
458 | files = (
459 | A5C936CC217C8EC800776DFC /* StyleableViewController.m in Sources */,
460 | A5C936C6217C84C500776DFC /* main.m in Sources */,
461 | A5C9369A217C82D100776DFC /* AppDelegate.m in Sources */,
462 | A5C93695217C82D100776DFC /* StyleableNavigationController.m in Sources */,
463 | );
464 | runOnlyForDeploymentPostprocessing = 0;
465 | };
466 | /* End PBXSourcesBuildPhase section */
467 |
468 | /* Begin PBXTargetDependency section */
469 | 935503161EF2F4F300FD428F /* PBXTargetDependency */ = {
470 | isa = PBXTargetDependency;
471 | target = 9390063D1EE2038900BF6787 /* Gagat */;
472 | targetProxy = 935503151EF2F4F300FD428F /* PBXContainerItemProxy */;
473 | };
474 | 939006441EE2038900BF6787 /* PBXTargetDependency */ = {
475 | isa = PBXTargetDependency;
476 | target = 9390063D1EE2038900BF6787 /* Gagat */;
477 | targetProxy = 939006431EE2038900BF6787 /* PBXContainerItemProxy */;
478 | };
479 | A5C936A0217C83DE00776DFC /* PBXTargetDependency */ = {
480 | isa = PBXTargetDependency;
481 | target = 9355030A1EF2F4CA00FD428F /* GagatObjectiveC */;
482 | targetProxy = A5C9369F217C83DE00776DFC /* PBXContainerItemProxy */;
483 | };
484 | A5C936D0217C924A00776DFC /* PBXTargetDependency */ = {
485 | isa = PBXTargetDependency;
486 | target = 9390063D1EE2038900BF6787 /* Gagat */;
487 | targetProxy = A5C936CF217C924A00776DFC /* PBXContainerItemProxy */;
488 | };
489 | /* End PBXTargetDependency section */
490 |
491 | /* Begin PBXVariantGroup section */
492 | 939006231EE2024700BF6787 /* LaunchScreen.storyboard */ = {
493 | isa = PBXVariantGroup;
494 | children = (
495 | 939006241EE2024700BF6787 /* Base */,
496 | );
497 | name = LaunchScreen.storyboard;
498 | sourceTree = "";
499 | };
500 | 939006251EE2024700BF6787 /* Main.storyboard */ = {
501 | isa = PBXVariantGroup;
502 | children = (
503 | 939006261EE2024700BF6787 /* Base */,
504 | );
505 | name = Main.storyboard;
506 | sourceTree = "";
507 | };
508 | A5C9368E217C82D100776DFC /* LaunchScreen.storyboard */ = {
509 | isa = PBXVariantGroup;
510 | children = (
511 | A5C9368F217C82D100776DFC /* Base */,
512 | );
513 | name = LaunchScreen.storyboard;
514 | sourceTree = "";
515 | };
516 | /* End PBXVariantGroup section */
517 |
518 | /* Begin XCBuildConfiguration section */
519 | 935503101EF2F4CA00FD428F /* Debug */ = {
520 | isa = XCBuildConfiguration;
521 | buildSettings = {
522 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
523 | CLANG_ENABLE_MODULES = YES;
524 | CODE_SIGN_IDENTITY = "";
525 | CURRENT_PROJECT_VERSION = 1;
526 | DEFINES_MODULE = YES;
527 | DEVELOPMENT_TEAM = "";
528 | DYLIB_COMPATIBILITY_VERSION = 1;
529 | DYLIB_CURRENT_VERSION = 1;
530 | DYLIB_INSTALL_NAME_BASE = "@rpath";
531 | INFOPLIST_FILE = GagatObjectiveC/Info.plist;
532 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
533 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
534 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
535 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatObjectiveC;
536 | PRODUCT_NAME = "$(TARGET_NAME)";
537 | SKIP_INSTALL = YES;
538 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
539 | SWIFT_VERSION = 4.2;
540 | VERSIONING_SYSTEM = "apple-generic";
541 | VERSION_INFO_PREFIX = "";
542 | };
543 | name = Debug;
544 | };
545 | 935503111EF2F4CA00FD428F /* Release */ = {
546 | isa = XCBuildConfiguration;
547 | buildSettings = {
548 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
549 | CLANG_ENABLE_MODULES = YES;
550 | CODE_SIGN_IDENTITY = "";
551 | CURRENT_PROJECT_VERSION = 1;
552 | DEFINES_MODULE = YES;
553 | DEVELOPMENT_TEAM = "";
554 | DYLIB_COMPATIBILITY_VERSION = 1;
555 | DYLIB_CURRENT_VERSION = 1;
556 | DYLIB_INSTALL_NAME_BASE = "@rpath";
557 | INFOPLIST_FILE = GagatObjectiveC/Info.plist;
558 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
559 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
560 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
561 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatObjectiveC;
562 | PRODUCT_NAME = "$(TARGET_NAME)";
563 | SKIP_INSTALL = YES;
564 | SWIFT_VERSION = 4.2;
565 | VERSIONING_SYSTEM = "apple-generic";
566 | VERSION_INFO_PREFIX = "";
567 | };
568 | name = Release;
569 | };
570 | 9386EDEA1E577236009079B6 /* Debug */ = {
571 | isa = XCBuildConfiguration;
572 | buildSettings = {
573 | ALWAYS_SEARCH_USER_PATHS = NO;
574 | CLANG_ANALYZER_NONNULL = YES;
575 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
576 | CLANG_CXX_LIBRARY = "libc++";
577 | CLANG_ENABLE_MODULES = YES;
578 | CLANG_ENABLE_OBJC_ARC = YES;
579 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
580 | CLANG_WARN_BOOL_CONVERSION = YES;
581 | CLANG_WARN_COMMA = YES;
582 | CLANG_WARN_CONSTANT_CONVERSION = YES;
583 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
584 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
585 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
586 | CLANG_WARN_EMPTY_BODY = YES;
587 | CLANG_WARN_ENUM_CONVERSION = YES;
588 | CLANG_WARN_INFINITE_RECURSION = YES;
589 | CLANG_WARN_INT_CONVERSION = YES;
590 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
591 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
592 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
593 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
594 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
595 | CLANG_WARN_STRICT_PROTOTYPES = YES;
596 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
597 | CLANG_WARN_UNREACHABLE_CODE = YES;
598 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
599 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
600 | COPY_PHASE_STRIP = NO;
601 | DEBUG_INFORMATION_FORMAT = dwarf;
602 | ENABLE_STRICT_OBJC_MSGSEND = YES;
603 | ENABLE_TESTABILITY = YES;
604 | GCC_C_LANGUAGE_STANDARD = gnu99;
605 | GCC_DYNAMIC_NO_PIC = NO;
606 | GCC_NO_COMMON_BLOCKS = YES;
607 | GCC_OPTIMIZATION_LEVEL = 0;
608 | GCC_PREPROCESSOR_DEFINITIONS = (
609 | "DEBUG=1",
610 | "$(inherited)",
611 | );
612 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
613 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
614 | GCC_WARN_UNDECLARED_SELECTOR = YES;
615 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
616 | GCC_WARN_UNUSED_FUNCTION = YES;
617 | GCC_WARN_UNUSED_VARIABLE = YES;
618 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
619 | MTL_ENABLE_DEBUG_INFO = YES;
620 | ONLY_ACTIVE_ARCH = YES;
621 | SDKROOT = iphoneos;
622 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
623 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
624 | TARGETED_DEVICE_FAMILY = "1,2";
625 | };
626 | name = Debug;
627 | };
628 | 9386EDEB1E577236009079B6 /* Release */ = {
629 | isa = XCBuildConfiguration;
630 | buildSettings = {
631 | ALWAYS_SEARCH_USER_PATHS = NO;
632 | CLANG_ANALYZER_NONNULL = YES;
633 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
634 | CLANG_CXX_LIBRARY = "libc++";
635 | CLANG_ENABLE_MODULES = YES;
636 | CLANG_ENABLE_OBJC_ARC = YES;
637 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
638 | CLANG_WARN_BOOL_CONVERSION = YES;
639 | CLANG_WARN_COMMA = YES;
640 | CLANG_WARN_CONSTANT_CONVERSION = YES;
641 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
642 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
643 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
644 | CLANG_WARN_EMPTY_BODY = YES;
645 | CLANG_WARN_ENUM_CONVERSION = YES;
646 | CLANG_WARN_INFINITE_RECURSION = YES;
647 | CLANG_WARN_INT_CONVERSION = YES;
648 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
649 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
650 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
651 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
652 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
653 | CLANG_WARN_STRICT_PROTOTYPES = YES;
654 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
655 | CLANG_WARN_UNREACHABLE_CODE = YES;
656 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
657 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
658 | COPY_PHASE_STRIP = NO;
659 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
660 | ENABLE_NS_ASSERTIONS = NO;
661 | ENABLE_STRICT_OBJC_MSGSEND = YES;
662 | GCC_C_LANGUAGE_STANDARD = gnu99;
663 | GCC_NO_COMMON_BLOCKS = YES;
664 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
665 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
666 | GCC_WARN_UNDECLARED_SELECTOR = YES;
667 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
668 | GCC_WARN_UNUSED_FUNCTION = YES;
669 | GCC_WARN_UNUSED_VARIABLE = YES;
670 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
671 | MTL_ENABLE_DEBUG_INFO = NO;
672 | SDKROOT = iphoneos;
673 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
674 | TARGETED_DEVICE_FAMILY = "1,2";
675 | VALIDATE_PRODUCT = YES;
676 | };
677 | name = Release;
678 | };
679 | 9386EDED1E577236009079B6 /* Debug */ = {
680 | isa = XCBuildConfiguration;
681 | buildSettings = {
682 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
683 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
684 | DEVELOPMENT_TEAM = "";
685 | INFOPLIST_FILE = "Gagat Example/Info.plist";
686 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
687 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
688 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatExample;
689 | PRODUCT_NAME = "$(TARGET_NAME)";
690 | SWIFT_VERSION = 5.0;
691 | };
692 | name = Debug;
693 | };
694 | 9386EDEE1E577236009079B6 /* Release */ = {
695 | isa = XCBuildConfiguration;
696 | buildSettings = {
697 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
698 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
699 | DEVELOPMENT_TEAM = "";
700 | INFOPLIST_FILE = "Gagat Example/Info.plist";
701 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
702 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
703 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatExample;
704 | PRODUCT_NAME = "$(TARGET_NAME)";
705 | SWIFT_VERSION = 5.0;
706 | };
707 | name = Release;
708 | };
709 | 939006491EE2038900BF6787 /* Debug */ = {
710 | isa = XCBuildConfiguration;
711 | buildSettings = {
712 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
713 | CLANG_ENABLE_MODULES = YES;
714 | CODE_SIGN_IDENTITY = "";
715 | CURRENT_PROJECT_VERSION = 1;
716 | DEFINES_MODULE = YES;
717 | DEVELOPMENT_TEAM = "";
718 | DYLIB_COMPATIBILITY_VERSION = 1;
719 | DYLIB_CURRENT_VERSION = 1;
720 | DYLIB_INSTALL_NAME_BASE = "@rpath";
721 | INFOPLIST_FILE = Gagat/Info.plist;
722 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
723 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
724 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
725 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.Gagat;
726 | PRODUCT_NAME = "$(TARGET_NAME)";
727 | SKIP_INSTALL = YES;
728 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
729 | SWIFT_VERSION = 5.0;
730 | VERSIONING_SYSTEM = "apple-generic";
731 | VERSION_INFO_PREFIX = "";
732 | };
733 | name = Debug;
734 | };
735 | 9390064A1EE2038900BF6787 /* Release */ = {
736 | isa = XCBuildConfiguration;
737 | buildSettings = {
738 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
739 | CLANG_ENABLE_MODULES = YES;
740 | CODE_SIGN_IDENTITY = "";
741 | CURRENT_PROJECT_VERSION = 1;
742 | DEFINES_MODULE = YES;
743 | DEVELOPMENT_TEAM = "";
744 | DYLIB_COMPATIBILITY_VERSION = 1;
745 | DYLIB_CURRENT_VERSION = 1;
746 | DYLIB_INSTALL_NAME_BASE = "@rpath";
747 | INFOPLIST_FILE = Gagat/Info.plist;
748 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
749 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
750 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
751 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.Gagat;
752 | PRODUCT_NAME = "$(TARGET_NAME)";
753 | SKIP_INSTALL = YES;
754 | SWIFT_VERSION = 5.0;
755 | VERSIONING_SYSTEM = "apple-generic";
756 | VERSION_INFO_PREFIX = "";
757 | };
758 | name = Release;
759 | };
760 | A5C93683217C826A00776DFC /* Debug */ = {
761 | isa = XCBuildConfiguration;
762 | buildSettings = {
763 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
764 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
765 | DEVELOPMENT_TEAM = "";
766 | INFOPLIST_FILE = "GagatObjectiveC Example/Info.plist";
767 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
768 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
769 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatObjCExample;
770 | PRODUCT_NAME = "$(TARGET_NAME)";
771 | SWIFT_VERSION = 4.2;
772 | };
773 | name = Debug;
774 | };
775 | A5C93684217C826A00776DFC /* Release */ = {
776 | isa = XCBuildConfiguration;
777 | buildSettings = {
778 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
779 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
780 | DEVELOPMENT_TEAM = "";
781 | INFOPLIST_FILE = "GagatObjectiveC Example/Info.plist";
782 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
783 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
784 | PRODUCT_BUNDLE_IDENTIFIER = se.cocoabeans.GagatObjCExample;
785 | PRODUCT_NAME = "$(TARGET_NAME)";
786 | SWIFT_VERSION = 4.2;
787 | };
788 | name = Release;
789 | };
790 | /* End XCBuildConfiguration section */
791 |
792 | /* Begin XCConfigurationList section */
793 | 935503121EF2F4CA00FD428F /* Build configuration list for PBXNativeTarget "GagatObjectiveC" */ = {
794 | isa = XCConfigurationList;
795 | buildConfigurations = (
796 | 935503101EF2F4CA00FD428F /* Debug */,
797 | 935503111EF2F4CA00FD428F /* Release */,
798 | );
799 | defaultConfigurationIsVisible = 0;
800 | defaultConfigurationName = Release;
801 | };
802 | 9386EDD51E577236009079B6 /* Build configuration list for PBXProject "Gagat" */ = {
803 | isa = XCConfigurationList;
804 | buildConfigurations = (
805 | 9386EDEA1E577236009079B6 /* Debug */,
806 | 9386EDEB1E577236009079B6 /* Release */,
807 | );
808 | defaultConfigurationIsVisible = 0;
809 | defaultConfigurationName = Release;
810 | };
811 | 9386EDEC1E577236009079B6 /* Build configuration list for PBXNativeTarget "Gagat Example" */ = {
812 | isa = XCConfigurationList;
813 | buildConfigurations = (
814 | 9386EDED1E577236009079B6 /* Debug */,
815 | 9386EDEE1E577236009079B6 /* Release */,
816 | );
817 | defaultConfigurationIsVisible = 0;
818 | defaultConfigurationName = Release;
819 | };
820 | 939006481EE2038900BF6787 /* Build configuration list for PBXNativeTarget "Gagat" */ = {
821 | isa = XCConfigurationList;
822 | buildConfigurations = (
823 | 939006491EE2038900BF6787 /* Debug */,
824 | 9390064A1EE2038900BF6787 /* Release */,
825 | );
826 | defaultConfigurationIsVisible = 0;
827 | defaultConfigurationName = Release;
828 | };
829 | A5C93682217C826A00776DFC /* Build configuration list for PBXNativeTarget "GagatObjectiveC Example" */ = {
830 | isa = XCConfigurationList;
831 | buildConfigurations = (
832 | A5C93683217C826A00776DFC /* Debug */,
833 | A5C93684217C826A00776DFC /* Release */,
834 | );
835 | defaultConfigurationIsVisible = 0;
836 | defaultConfigurationName = Release;
837 | };
838 | /* End XCConfigurationList section */
839 | };
840 | rootObject = 9386EDD21E577236009079B6 /* Project object */;
841 | }
842 |
--------------------------------------------------------------------------------
/Gagat.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Gagat.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Gagat.xcodeproj/xcshareddata/xcschemes/Gagat.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/Gagat/AnimationUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationUtilities.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-02-17.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import QuartzCore
11 |
12 | private func distance(from source: CGPoint, to destination: CGPoint) -> CGFloat {
13 | return sqrt(pow(destination.x - source.x, 2) + pow(destination.y - source.y, 2))
14 | }
15 |
16 | private func timeRequiredToMove(from source: CGPoint, to destination: CGPoint, withVelocity velocity: CGPoint) -> TimeInterval {
17 | let distanceToMove = distance(from: source, to: destination)
18 | let velocityMagnitude = sqrt(pow(velocity.x, 2) + pow(velocity.y, 2))
19 | let requiredTime = TimeInterval(abs(distanceToMove / velocityMagnitude))
20 | return requiredTime
21 | }
22 |
23 | private func maximumReasonableTimeToMove(from source: CGPoint, to destination: CGPoint) -> TimeInterval {
24 | let minimumReasonableVelocity: CGFloat = 300.0 // points per second, chosen empirically
25 | let distanceToMove = distance(from: source, to: destination)
26 | return TimeInterval(distanceToMove / minimumReasonableVelocity)
27 | }
28 |
29 | func animate(_ layer: CALayer, to targetPoint: CGPoint, withVelocity velocity: CGPoint, completion: @escaping () -> Void) {
30 | let startPoint = layer.position
31 | layer.position = targetPoint
32 |
33 | let positionAnimation = CABasicAnimation(keyPath: "position")
34 | positionAnimation.duration = min(
35 | maximumReasonableTimeToMove(from: startPoint, to: targetPoint),
36 | timeRequiredToMove(from: startPoint, to: targetPoint, withVelocity: velocity)
37 | )
38 | positionAnimation.fromValue = NSValue(cgPoint: startPoint)
39 | positionAnimation.toValue = NSValue(cgPoint: targetPoint)
40 |
41 | CATransaction.begin()
42 | CATransaction.setCompletionBlock(completion)
43 |
44 | layer.add(positionAnimation, forKey: "position")
45 |
46 | CATransaction.commit()
47 | }
48 |
--------------------------------------------------------------------------------
/Gagat/Gagat.h:
--------------------------------------------------------------------------------
1 | //
2 | // Gagat.h
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-06-02.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for Gagat.
12 | FOUNDATION_EXPORT double GagatVersionNumber;
13 |
14 | //! Project version string for Gagat.
15 | FOUNDATION_EXPORT const unsigned char GagatVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Gagat/Gagat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Gagat.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-02-17.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | /// A type that knows how to toggle between two alternative visual styles.
13 | public protocol GagatStyleable {
14 | /// Activates the alternative style that is currently not active.
15 | ///
16 | /// This method is called by Gagat at the start of a transition
17 | /// and at the end of a _cancelled_ transition (to revert to the
18 | /// previous style).
19 | ///
20 | /// This method is required.
21 | func toggleActiveStyle()
22 |
23 | /// Called when the style transition is about to begin. `toggleActiveStyle()` will be called just after this.
24 | ///
25 | /// This method is optional.
26 | func styleTransitionWillBegin()
27 |
28 | /// Called when the style transition ended.
29 | ///
30 | /// This method is optional.
31 | func styleTransitionDidEnd()
32 | }
33 |
34 | /// Since styleTransitionWillBegin() and styleTransitionDidEnd() aren't considered as required to implement
35 | /// the core functionality of the GagatStyleable protocol, this extension provides default (empty) implementations
36 | /// of those functions. This makes implementing them in your GagatStyleable object optional.
37 | public extension GagatStyleable {
38 | func styleTransitionWillBegin() {}
39 | func styleTransitionDidEnd() {}
40 | }
41 |
42 | public struct Gagat {
43 |
44 | /// The `Configuration` struct allows clients to configure certain
45 | /// aspects of the transition.
46 | ///
47 | /// Initialize an empty instance of the struct to use the defaults.
48 | public struct Configuration {
49 | /// Controls how much the border between the new and
50 | /// previous style is deformed when panning. The larger the
51 | /// factor is, the more the border is deformed.
52 | /// Specify a factor of 0 to entirely disable the deformation.
53 | ///
54 | /// Defaults to 1.0.
55 | public let jellyFactor: Double
56 |
57 | public init(jellyFactor: Double = 1.0) {
58 | self.jellyFactor = jellyFactor
59 | }
60 | }
61 |
62 | /// Represents a configured transition and allows clients to
63 | /// access properties that can be modified after configuration.
64 | public struct TransitionHandle {
65 | private let coordinator: TransitionCoordinator
66 |
67 | fileprivate init(coordinator: TransitionCoordinator) {
68 | self.coordinator = coordinator
69 | }
70 |
71 | /// The pan gesture recognizer that Gagat uses to trigger and drive the
72 | /// transition.
73 | ///
74 | /// You may use this property to configure the minimum or maximum number
75 | /// of required touches if you don't want to use the default two-finger
76 | /// pan. You may also use it to setup dependencies between this gesture
77 | /// recognizer and any other gesture recognizers in your application.
78 | ///
79 | /// - important: You *must not* change the gesture recognizer's delegate
80 | /// or remove targets not added by the client.
81 | public var panGestureRecognizer: UIPanGestureRecognizer {
82 | return coordinator.panGestureRecognizer
83 | }
84 | }
85 |
86 | /// Configures everything that's needed by Gagat to begin handling the transition
87 | /// in the specified window.
88 | ///
89 | /// - important: You *must* keep a reference to the `TransitionHandle`
90 | /// returned by this method even if you don't intend to access
91 | /// any of its properties.
92 | /// All Gagat-related objects will be torn down when the
93 | /// handle is deallocated, and the client will need to call
94 | /// `Gagat.configure(for:with:using:)` again to re-enable
95 | /// the Gagat transition.
96 | ///
97 | /// - note: This method shouldn't be called multiple times for the same window
98 | /// unless the returned handle has been deallocated.
99 | ///
100 | /// - parameter window: The window that the user will pan in to trigger the
101 | /// transition.
102 | /// - parameter styleableObject: An object that conforms to `GagatStyleable` and
103 | /// which is responsible for toggling to the alternative style when
104 | /// the transition is triggered or cancelled.
105 | /// - parameter configuration: The configuration to use for the transition.
106 | ///
107 | /// - returns: A new instance of `TransitionHandle`.
108 | public static func configure(for window: UIWindow, with styleableObject: GagatStyleable, using configuration: Configuration = Configuration()) -> TransitionHandle {
109 | let coordinator = TransitionCoordinator(targetView: window, styleableObject: styleableObject, configuration: configuration)
110 | return TransitionHandle(coordinator: coordinator)
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Gagat/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Gagat/PessimisticPanGestureRecognizer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PessimisticPanGestureRecognizer.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-05-25.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import UIKit.UIGestureRecognizerSubclass
11 |
12 | /// `PessimisticPanGestureRecognizer` is a `UIPanGestureRecognizer` subclass that
13 | /// fails earlier than the base `UIPanGestureRecognizer` class.
14 | /// More specifically it fails if the user drags fewer than the minimum number
15 | /// of required fingers past a certain threshold (10pt).
16 | ///
17 | /// In Gagat, this is used as the pan gesture recognizer that drives the
18 | /// style transition. It is required in order to let the transition work
19 | /// in harmony with any `UIScrollViews` (e.g. `UITableView`) that exist in the
20 | /// application.
21 | class PessimisticPanGestureRecognizer: UIPanGestureRecognizer {
22 |
23 | override func touchesMoved(_ touches: Set, with event: UIEvent) {
24 | let hasLessThanNumberOfRequiredTouches = (event.allTouches?.count ?? 0) < minimumNumberOfTouches
25 | let hasDraggedPastFailureThreshold = absoluteDistanceFromStartingPoint < 10.0
26 | if hasLessThanNumberOfRequiredTouches && hasDraggedPastFailureThreshold {
27 | state = .failed
28 | } else {
29 | super.touchesMoved(touches, with: event)
30 | }
31 | }
32 |
33 | private var absoluteDistanceFromStartingPoint: CGFloat {
34 | let translation = self.translation(in: view)
35 | return sqrt(pow(translation.x, 2) + pow(translation.y, 2))
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Gagat/TransitionCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransitionCoordinator.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-02-17.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class TransitionCoordinator: NSObject {
13 |
14 | fileprivate enum State {
15 | case idle
16 | case tracking
17 | case transitioning
18 | }
19 |
20 | /// The view (or window) that the transition should occur in, and
21 | /// which the pan gesture recognizer is installed in.
22 | fileprivate let targetView: UIView
23 |
24 | fileprivate let configuration: Gagat.Configuration
25 | private let styleableObject: GagatStyleable
26 |
27 | private(set) var panGestureRecognizer: PessimisticPanGestureRecognizer!
28 |
29 | fileprivate var state = State.idle
30 |
31 | init(targetView: UIView, styleableObject: GagatStyleable, configuration: Gagat.Configuration) {
32 | self.targetView = targetView
33 | self.configuration = configuration
34 | self.styleableObject = styleableObject
35 |
36 | super.init()
37 |
38 | setupPanGestureRecognizer(in: targetView)
39 | }
40 |
41 | deinit {
42 | panGestureRecognizer.view?.removeGestureRecognizer(panGestureRecognizer)
43 | }
44 |
45 | // MARK: - Pan gesture recognizer
46 |
47 | private func setupPanGestureRecognizer(in targetView: UIView) {
48 | let panGestureRecognizer = PessimisticPanGestureRecognizer(target: self, action: #selector(panRecognizerDidChange(_:)))
49 | panGestureRecognizer.maximumNumberOfTouches = 2
50 | panGestureRecognizer.minimumNumberOfTouches = 2
51 | panGestureRecognizer.delegate = self
52 | targetView.addGestureRecognizer(panGestureRecognizer)
53 |
54 | self.panGestureRecognizer = panGestureRecognizer
55 | }
56 |
57 | @objc func panRecognizerDidChange(_ panRecognizer: PessimisticPanGestureRecognizer) {
58 | switch panRecognizer.state {
59 | case .began:
60 | beginInteractiveStyleTransition(withPanRecognizer: panRecognizer)
61 | case .changed:
62 | adjustMaskLayer(basedOn: panRecognizer)
63 | case .ended, .failed:
64 | endInteractiveStyleTransition(withPanRecognizer: panRecognizer)
65 | case .cancelled:
66 | cancelInteractiveStyleTransitionWithoutAnimation()
67 | default: break
68 | }
69 | }
70 |
71 | // MARK: - Interactive style transition
72 |
73 | /// During the interactive transition, this property contains a
74 | /// snapshot of the view when it was styled with the previous style
75 | /// (i.e. the style we're transitioning _from_).
76 | /// As the transition progresses, less and less of the snapshot view
77 | /// will be visible, revealing more of the real view which is styled
78 | /// with the new style.
79 | private var previousStyleTargetViewSnapshot: UIView?
80 |
81 | /// During the interactive transition, this property contains the layer
82 | /// used to mask the contents of `previousStyleTargetViewSnapshot`.
83 | /// When the user pans, the position and path of `snapshotMaskLayer` is
84 | /// adjusted to reflect the current translation of the pan recognizer.
85 | private var snapshotMaskLayer: CAShapeLayer?
86 |
87 | private func beginInteractiveStyleTransition(withPanRecognizer panRecognizer: PessimisticPanGestureRecognizer) {
88 |
89 | // Inform our object that we're about to start a transition.
90 | styleableObject.styleTransitionWillBegin()
91 |
92 | // We snapshot the targetView before applying the new style, and make sure
93 | // it's positioned on top of all the other content.
94 | previousStyleTargetViewSnapshot = targetView.snapshotView(afterScreenUpdates: false)
95 | targetView.addSubview(previousStyleTargetViewSnapshot!)
96 | targetView.bringSubviewToFront(previousStyleTargetViewSnapshot!)
97 |
98 | // When we have the snapshot we create a new mask layer that's used to
99 | // control how much of the previous view we display as the transition
100 | // progresses.
101 | snapshotMaskLayer = CAShapeLayer()
102 | snapshotMaskLayer?.path = UIBezierPath(rect: targetView.bounds).cgPath
103 | snapshotMaskLayer?.fillColor = UIColor.black.cgColor
104 | previousStyleTargetViewSnapshot?.layer.mask = snapshotMaskLayer
105 |
106 | // Now we're free to apply the new style. This won't be visible until
107 | // the user pans more since the snapshot is displayed on top of the
108 | // actual content.
109 | styleableObject.toggleActiveStyle()
110 |
111 | // Finally we make our first adjustment to the mask layer based on the
112 | // values of the pan recognizer.
113 | adjustMaskLayer(basedOn: panRecognizer)
114 |
115 | state = .tracking
116 | }
117 |
118 | private func adjustMaskLayer(basedOn panRecognizer: PessimisticPanGestureRecognizer) {
119 | adjustMaskLayerPosition(basedOn: panRecognizer)
120 | adjustMaskLayerPath(basedOn: panRecognizer)
121 | }
122 |
123 | private func adjustMaskLayerPosition(basedOn panRecognizer: PessimisticPanGestureRecognizer) {
124 | // We need to disable implicit animations since we don't want to
125 | // animate the position change of the mask layer.
126 | CATransaction.begin()
127 | CATransaction.setDisableActions(true)
128 |
129 | let verticalTranslation = panRecognizer.translation(in: targetView).y
130 | if verticalTranslation < 0.0 {
131 | // We wan't to prevent the user from moving the mask layer out the
132 | // top of the targetView, since doing so would show the new style at
133 | // the bottom of the targetView instead.
134 | //
135 | // By resetting the translation we make sure there's no visual
136 | // delay between when the user tries to pan upwards and when they
137 | // start panning downwards again.
138 | panRecognizer.setTranslation(.zero, in: targetView)
139 | snapshotMaskLayer?.frame.origin.y = 0.0
140 | } else {
141 | // Simply move the mask layer as much as the user has panned.
142 | // Note that if we had used the _location_ of the pan recognizer
143 | // instead of the _translation_, the top of the mask layer would
144 | // follow the fingers exactly. Using the translation results in a
145 | // better user experience since the location of the mask layer is
146 | // instead relative to the distance moved, just like when moving a
147 | // piece of paper with our fingertips.
148 | snapshotMaskLayer?.frame.origin.y = verticalTranslation
149 | }
150 |
151 | CATransaction.commit()
152 | }
153 |
154 | private func adjustMaskLayerPath(basedOn panRecognizer: PessimisticPanGestureRecognizer) {
155 | let maskingPath = UIBezierPath()
156 |
157 | // Top-left corner...
158 | maskingPath.move(to: .zero)
159 |
160 | // ...arc to top-right corner...
161 | // This is all the code that is required to get the bouncy effect.
162 | // Since the control point of the quad curve depends on the velocity
163 | // of the pan recognizer, the path will "deform" more for a larger
164 | // velocity.
165 | // We don't need to do anything to animate the path back to its
166 | // non-deformed state since the pan gesture recognizer's target method
167 | // (panRecognizerDidChange(_:) in our case) is called periodically
168 | // even when the user stops moving their finger (until the velocity
169 | // reaches 0).
170 | // Note: To increase the bouncy effect, decrease the `damping` value.
171 | let damping = configuration.jellyFactor > 0.0 ? CGFloat(45.0 / configuration.jellyFactor) : 0.0
172 | let verticalOffset = damping > 0.0 ? panRecognizer.velocity(in: targetView).y / damping : 0.0
173 | let horizontalTouchLocation = panRecognizer.location(in: targetView).x
174 | maskingPath.addQuadCurve(to: CGPoint(x: targetView.bounds.maxX, y: 0.0), controlPoint: CGPoint(x: horizontalTouchLocation, y: verticalOffset))
175 |
176 | // ...to bottom-right corner...
177 | maskingPath.addLine(to: CGPoint(x: targetView.bounds.maxX, y: targetView.bounds.maxY))
178 |
179 | // ...to bottom-left corner...
180 | maskingPath.addLine(to: CGPoint(x: 0.0, y: targetView.bounds.maxY))
181 |
182 | // ...and close the path.
183 | maskingPath.close()
184 |
185 | snapshotMaskLayer?.path = maskingPath.cgPath
186 | }
187 |
188 | private func endInteractiveStyleTransition(withPanRecognizer panRecognizer: PessimisticPanGestureRecognizer) {
189 | let velocity = panRecognizer.velocity(in: targetView)
190 | let translation = panRecognizer.translation(in: targetView)
191 |
192 | let isMovingDownwards = velocity.y > 0.0
193 | let hasPassedThreshold = translation.y > targetView.bounds.midY
194 |
195 | // We support both completing the transition and cancelling the transition.
196 | // The transition to the new style should be completed if the user is panning
197 | // downwards or if they've panned enough that more than half of the new view
198 | // is already shown.
199 | let shouldCompleteTransition = isMovingDownwards || hasPassedThreshold
200 |
201 | if shouldCompleteTransition {
202 | completeInteractiveStyleTransition(withVelocity: velocity)
203 | } else {
204 | cancelInteractiveStyleTransition(withVelocity: velocity)
205 | }
206 | }
207 |
208 | private func cancelInteractiveStyleTransitionWithoutAnimation() {
209 | styleableObject.toggleActiveStyle()
210 | cleanupAfterInteractiveStyleTransition()
211 | state = .idle
212 | styleableObject.styleTransitionDidEnd()
213 | }
214 |
215 | private func cancelInteractiveStyleTransition(withVelocity velocity: CGPoint) {
216 | guard let snapshotMaskLayer = snapshotMaskLayer else {
217 | return
218 | }
219 |
220 | state = .transitioning
221 |
222 | // When cancelling the transition we simply animate the mask layer to its original
223 | // location (which means that the entire previous style snapshot is shown), then
224 | // reset the style to the previous style and remove the snapshot.
225 | animate(snapshotMaskLayer, to: .zero, withVelocity: velocity) {
226 | self.styleableObject.toggleActiveStyle()
227 | self.cleanupAfterInteractiveStyleTransition()
228 | self.state = .idle
229 | self.styleableObject.styleTransitionDidEnd()
230 | }
231 | }
232 |
233 | private func completeInteractiveStyleTransition(withVelocity velocity: CGPoint) {
234 | guard let snapshotMaskLayer = snapshotMaskLayer else {
235 | return
236 | }
237 |
238 | state = .transitioning
239 |
240 | // When completing the transition we slide the mask layer down to the bottom of
241 | // the targetView and then remove the snapshot. The further down the mask layer is,
242 | // the more of the underlying view is visible. When the mask layer reaches the
243 | // bottom of the targetView, the entire underlying view will be visible so removing
244 | // the snapshot will have no visual effect.
245 | let targetLocation = CGPoint(x: 0.0, y: targetView.bounds.maxY)
246 | animate(snapshotMaskLayer, to: targetLocation, withVelocity: velocity) {
247 | self.cleanupAfterInteractiveStyleTransition()
248 | self.state = .idle
249 | self.styleableObject.styleTransitionDidEnd()
250 | }
251 | }
252 |
253 | private func cleanupAfterInteractiveStyleTransition() {
254 | self.previousStyleTargetViewSnapshot?.removeFromSuperview()
255 | self.previousStyleTargetViewSnapshot = nil
256 | self.snapshotMaskLayer = nil
257 | }
258 | }
259 |
260 | extension TransitionCoordinator: UIGestureRecognizerDelegate {
261 | private typealias Degrees = Double
262 |
263 | private enum Direction {
264 | case up, down, left, right
265 | }
266 |
267 | func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
268 | guard let panRecognizer = gestureRecognizer as? PessimisticPanGestureRecognizer else {
269 | return true
270 | }
271 |
272 | guard state == .idle else {
273 | return false
274 | }
275 |
276 | let translation = panRecognizer.translation(in: targetView)
277 | let panningAngle: Degrees = atan2(Double(translation.y), Double(translation.x)) * 360 / (Double.pi * 2)
278 | let panningDirection = direction(for: panningAngle)
279 | return panningDirection == .down
280 | }
281 |
282 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
283 | // This prevents other pan gesture recognizerns (such as the one in scroll views) from interfering with the Gagat gesture.
284 | return otherGestureRecognizer is UIPanGestureRecognizer
285 | }
286 |
287 | private func direction(for angle: Degrees) -> Direction {
288 | switch angle {
289 | case 45.0...135.0: return .down
290 | case 135.0...225.0: return .left
291 | case 225.0...315.0: return .up
292 | default: return .right
293 | }
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | @import UIKit;
2 |
3 | @interface AppDelegate : UIResponder
4 |
5 | @end
6 |
7 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 | #import "StyleableNavigationController.h"
3 | #import "StyleableViewController.h"
4 | @import GagatObjectiveC.Swift;
5 |
6 | @interface AppDelegate ()
7 |
8 | @property (nonatomic) GGTTransitionHandle *transitionHandle;
9 |
10 | @end
11 |
12 | @implementation AppDelegate
13 |
14 | @synthesize window = _window;
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
17 | self.window = [[UIWindow alloc] init];
18 |
19 | StyleableNavigationController *navigationController = [[StyleableNavigationController alloc] initWithRootViewController:[[StyleableViewController alloc] init]];
20 | self.window.rootViewController = navigationController;
21 |
22 | // Configure Gagat for the applications only window using a jelly factor that is
23 | // slightly larger than the default factor of 1.0. We'll use the root view controller
24 | // as the styleable object, but you can use any object that conforms to `GGTStyleable`.
25 | //
26 | // Note: Make sure you keep a reference to the value returned from `configureForWindow:withStyleableObject:usingConfiguration:`.
27 | // If this object is deallocated then the Gagat transition will no longer work.
28 | GGTConfiguration *configuration = [[GGTConfiguration alloc] initWithJellyFactor:1.5];
29 | self.transitionHandle = [GGTManager configureForWindow:self.window withStyleableObject:navigationController usingConfiguration:configuration];
30 |
31 | [self.window makeKeyAndVisible];
32 |
33 | return YES;
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/GagatObjectiveC Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/GagatObjectiveC Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/StyleableNavigationController.h:
--------------------------------------------------------------------------------
1 | @import UIKit;
2 | @import GagatObjectiveC.Swift;
3 |
4 | @interface StyleableNavigationController: UINavigationController
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/StyleableNavigationController.m:
--------------------------------------------------------------------------------
1 | #import "StyleableNavigationController.h"
2 |
3 | @interface StyleableNavigationController ()
4 |
5 | @property (nonatomic) BOOL useDarkMode;
6 |
7 | @end
8 |
9 | @implementation StyleableNavigationController
10 |
11 | - (void)styleTransitionWillBegin {
12 | // Do any work you might need to do once the transition has completed.
13 | UIViewController *topViewController = self.topViewController;
14 | if ([topViewController conformsToProtocol:@protocol(GGTStyleable)]) {
15 | [(id)topViewController styleTransitionWillBegin];
16 | }
17 | }
18 |
19 | - (void)styleTransitionDidEnd {
20 | // Do any work you might need to do once the transition has completed.
21 | UIViewController *topViewController = self.topViewController;
22 | if ([topViewController conformsToProtocol:@protocol(GGTStyleable)]) {
23 | [(id)topViewController styleTransitionDidEnd];
24 | }
25 | }
26 |
27 | - (void)toggleActiveStyle {
28 | self.useDarkMode = !self.useDarkMode;
29 |
30 | // It's up to us to get any child view controllers to
31 | // toggle their active style. In this example application we've made
32 | // the child view controller also conform to `GGTStyleable`, but
33 | // this is not required by Gagat.
34 | UIViewController *topViewController = self.topViewController;
35 | if ([topViewController conformsToProtocol:@protocol(GGTStyleable)]) {
36 | [(id)topViewController toggleActiveStyle];
37 | }
38 | }
39 |
40 | - (void)setUseDarkMode:(BOOL)useDarkMode {
41 | _useDarkMode = useDarkMode;
42 |
43 | self.navigationBar.barStyle = useDarkMode ? UIBarStyleBlack : UIBarStyleDefault;
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/StyleableViewController.h:
--------------------------------------------------------------------------------
1 | @import UIKit;
2 | @import GagatObjectiveC.Swift;
3 |
4 | @interface StyleableViewController: UIViewController
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/StyleableViewController.m:
--------------------------------------------------------------------------------
1 | #import "StyleableViewController.h"
2 |
3 | @interface StyleableViewController ()
4 |
5 | @property (nonatomic) BOOL useDarkMode;
6 | @property (nonatomic) UILabel *label;
7 |
8 | @end
9 |
10 | @implementation StyleableViewController
11 |
12 | - (void)loadView {
13 | self.label = [[UILabel alloc] init];
14 | self.label.text = @"Gagat";
15 | self.label.textAlignment = NSTextAlignmentCenter;
16 | self.view = self.label;
17 |
18 | self.title = @"Gagat";
19 | }
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | [self applyStyle];
25 | }
26 |
27 | - (void)styleTransitionWillBegin {
28 | // Do any work you might need to do once the transition has completed.
29 | }
30 |
31 | - (void)styleTransitionDidEnd {
32 | // Do any work you might need to do once the transition has completed.
33 | }
34 |
35 | - (void)toggleActiveStyle {
36 | self.useDarkMode = !self.useDarkMode;
37 | }
38 |
39 | - (void)setUseDarkMode:(BOOL)useDarkMode {
40 | _useDarkMode = useDarkMode;
41 | [self applyStyle];
42 | }
43 |
44 | - (void)applyStyle {
45 | self.view.backgroundColor = self.useDarkMode ? [UIColor colorWithWhite:0.15f alpha:1] : UIColor.whiteColor;
46 | self.label.textColor = self.useDarkMode ? UIColor.lightTextColor : UIColor.darkTextColor;
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/GagatObjectiveC Example/main.m:
--------------------------------------------------------------------------------
1 | @import UIKit;
2 | #import "AppDelegate.h"
3 |
4 | int main(int argc, char * argv[]) {
5 | @autoreleasepool {
6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/GagatObjectiveC/Gagat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GagatObjectiveC.swift
3 | // Gagat
4 | //
5 | // Created by Tim Andersson on 2017-06-12.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | //
10 | // +---------------------------------------------------------------------------------+
11 | // | This file contains an Objective-C bridge for Gagat. It is the only component of |
12 | // | the GagatObjectiveC target and has a dependency on the original Gagat target. |
13 | // +---------------------------------------------------------------------------------+
14 | //
15 |
16 | import Foundation
17 | import Gagat
18 |
19 | /// A type that knows how to toggle between two alternative visual styles.
20 | @objc public protocol GGTStyleable {
21 | /// Activates the alternative style that is currently not active.
22 | ///
23 | /// This method is called by Gagat at the start of a transition
24 | /// and at the end of a _cancelled_ transition (to revert to the
25 | /// previous style).
26 | @objc func toggleActiveStyle()
27 |
28 | /// Called when the style transition is about to begin. `toggleActiveStyle()` will be called just after this.
29 | @objc optional func styleTransitionWillBegin()
30 |
31 | /// Called when the style transition ended.
32 | @objc optional func styleTransitionDidEnd()
33 | }
34 |
35 | /// The `GGTConfiguration` class allows clients to configure certain
36 | /// aspects of the transition.
37 | ///
38 | /// Initialize an empty instance of the class to use the defaults.
39 | public class GGTConfiguration: NSObject {
40 | /// Controls how much the border between the new and
41 | /// previous style is deformed when panning. The larger the
42 | /// factor is, the more the border is deformed.
43 | /// Specify a factor of 0 to entirely disable the deformation.
44 | ///
45 | /// Defaults to 1.0.
46 | @objc public let jellyFactor: Double
47 |
48 | @objc public init(jellyFactor: Double = 1.0) {
49 | self.jellyFactor = jellyFactor
50 | }
51 |
52 | fileprivate var toSwiftRepresentation: Gagat.Configuration {
53 | return Gagat.Configuration(jellyFactor: jellyFactor)
54 | }
55 | }
56 |
57 | /// Represents a configured transition and allows clients to
58 | /// access properties that can be modified after configuration.
59 | public class GGTTransitionHandle: NSObject {
60 | private let wrappedHandle: Gagat.TransitionHandle
61 |
62 | fileprivate init(byWrapping handle: Gagat.TransitionHandle) {
63 | wrappedHandle = handle
64 | }
65 |
66 | /// The pan gesture recognizer that Gagat uses to trigger and drive the
67 | /// transition.
68 | ///
69 | /// You may use this property to configure the minimum or maximum number
70 | /// of required touches if you don't want to use the default two-finger
71 | /// pan. You may also use it to setup dependencies between this gesture
72 | /// recognizer and any other gesture recognizers in your application.
73 | ///
74 | /// - important: You *must not* change the gesture recognizer's delegate
75 | /// or remove targets not added by the client.
76 | @objc public var panGestureRecognizer: UIPanGestureRecognizer {
77 | return wrappedHandle.panGestureRecognizer
78 | }
79 | }
80 |
81 | public class GGTManager: NSObject {
82 |
83 | /// Configures everything that's needed by Gagat to begin handling the transition
84 | /// in the specified window.
85 | ///
86 | /// - important: You *must* keep a reference to the `GGTTransitionHandle`
87 | /// returned by this method even if you don't intend to access
88 | /// any of its properties.
89 | /// All Gagat-related objects will be torn down when the
90 | /// handle is deallocated, and the client will need to call
91 | /// `-[GGTManager configureForWindow:withStyleableObject:usingConfiguration:]`
92 | /// again to re-enable the Gagat transition.
93 | ///
94 | /// - note: This method shouldn't be called multiple times for the same window
95 | /// unless the returned handle has been deallocated.
96 | ///
97 | /// - parameter window: The window that the user will pan in to trigger the
98 | /// transition.
99 | /// - parameter styleableObject: An object that conforms to `GGTStyleable` and
100 | /// which is responsible for toggling to the alternative style when
101 | /// the transition is triggered or cancelled.
102 | /// - parameter configuration: The configuration to use for the transition.
103 | ///
104 | /// - returns: A new instance of `GGTTransitionHandle`.
105 | @objc public class func configure(forWindow window: UIWindow, withStyleableObject styleableObject: GGTStyleable, usingConfiguration configuration: GGTConfiguration = GGTConfiguration()) -> GGTTransitionHandle {
106 | let styleableObjectProxy = GagatStyleableSwiftToObjCProxy(target: styleableObject)
107 | let handle = Gagat.configure(for: window, with: styleableObjectProxy, using: configuration.toSwiftRepresentation)
108 | return GGTTransitionHandle(byWrapping: handle)
109 | }
110 |
111 | }
112 |
113 | /// `GagatStyleableSwiftToObjCProxy` is used internally to bridge the Swift-only
114 | /// `GagatStyleable` type to the `GGTStyleable` type.
115 | private struct GagatStyleableSwiftToObjCProxy: GagatStyleable {
116 | private let target: GGTStyleable
117 |
118 | init(target: GGTStyleable) {
119 | self.target = target
120 | }
121 |
122 | func toggleActiveStyle() {
123 | target.toggleActiveStyle()
124 | }
125 |
126 | func styleTransitionWillBegin() {
127 | if let targetImplementation = target.styleTransitionWillBegin {
128 | targetImplementation()
129 | }
130 | }
131 |
132 | func styleTransitionDidEnd() {
133 | if let targetImplementation = target.styleTransitionDidEnd {
134 | targetImplementation()
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/GagatObjectiveC/GagatObjectiveC.h:
--------------------------------------------------------------------------------
1 | //
2 | // GagatObjectiveC.h
3 | // GagatObjectiveC
4 | //
5 | // Created by Tim Andersson on 2017-06-15.
6 | // Copyright © 2017 Cocoabeans Software. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for GagatObjectiveC.
12 | FOUNDATION_EXPORT double GagatObjectiveCVersionNumber;
13 |
14 | //! Project version string for GagatObjectiveC.
15 | FOUNDATION_EXPORT const unsigned char GagatObjectiveCVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/GagatObjectiveC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright 2017 Cocoabeans Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # What is Gagat?
4 | []()
5 | [](https://swift.org)
6 | []()
7 | [](https://github.com/Carthage/Carthage)
8 | [](https://raw.githubusercontent.com/Boerworz/Gagat/master/LICENSE)
9 |
10 | Gagat is a small Swift library that makes it easy to add a delightful, interactive way to switch between two different themes in your iOS application using a two-finger pan. The library was designed primarily for applications that support a "dark mode", and is heavily inspired by the Night Mode transition in [Castro 2](http://supertop.co/castro).
11 |
12 |
13 |
14 | ### What Gagat is not
15 | Gagat is **not** a library for styling your iOS applications. You must write all the styling logic yourself without any help from Gagat, and then call your styling code from your implementation of `GagatStyleable.toggleActiveStyle()`. If you are unsure of how to implement the styling, the Example app included with Gagat showcases one way to support different themes in an application by using [configuration models](http://www.jessesquires.com/enums-as-configs/).
16 |
17 | ## Requirements
18 | Gagat is written in Swift 5.0 and requires Xcode 10.2. It runs on iOS 10.0+ and can be used from both Swift and Objective-C clients.
19 |
20 | ## Installation
21 |
22 | You can either install Gagat using [Carthage] \(recommended) or by adding Gagat as a subproject.
23 |
24 | #### Carthage
25 |
26 | The recommended way to install Gagat is using [Carthage]. Simply add `github "Boerworz/Gagat" ~> 3.0` to your `Cartfile`, run a suitable Carthage command (such as `bootstrap`) and then add the framework(s) to your project. If you're using Gagat from Swift you only need `Gagat.framework`, but for Objective-C clients you need both `Gagat.framework` and `GagatObjectiveC.framework`.
27 |
28 | #### Adding Gagat as a subproject
29 |
30 | If you don't use [Carthage] to manage your dependencies then adding Gagat as a subproject is the easiest way to integrate Gagat. To do this simply download an [archive of the master branch](https://github.com/Boerworz/Gagat/archive/master.zip) and copy or move the entire directory to your project directory. When that's done, drag `Gagat.xcodeproj` from the Finder into your project organizer in Xcode. You should now be able to add the Gagat framework(s) as Embedded Binaries to your target. If you're using Gagat from Swift you only need `Gagat.framework`, but for Objective-C clients you need both `Gagat.framework` and `GagatObjectiveC.framework`. If you're unsure of how to do add frameworks to your project, please refer to [Apple's Technical Note on the topic](https://developer.apple.com/library/content/technotes/tn2435/_index.html#//apple_ref/doc/uid/DTS40017543-CH1-EMBED_IN_APP_SECTION).
31 |
32 | ## Usage
33 | To support Gagat in your iOS application there's two things you need to do (apart from `import`ing Gagat):
34 |
35 | #### 1. Conform to `GagatStyleable`
36 | In order for Gagat to be able to trigger the style change in your application you must provide it with an object that conforms to `GagatStyleable`. This object could be your root view controller, a specialized `StyleManager` kind of object, your app delegate, or any other object that fits your architecture.
37 |
38 | The only requirement in the `GagatStyleable` protocol is that you implement a `toggleActiveStyle()` method. When this method is invoked you should switch to the theme that is currently inactive, e.g. switch from a light theme to a dark theme or vice versa. It's not strictly a requirement, but for the best results you should attempt to have completed the style change before you return from `toggleActiveStyle()` (i.e. avoid asynchronous calls if possible).
39 |
40 | #### 2. Call `Gagat.configure(for:with:using:)`
41 | This is typically done in your implementation of `application(_:didFinishLaunchingWithOptions:)` and tells Gagat to get ready to handle the interactive transition in the specified window (probably your application's only window). The second argument is your object that conforms to `GagatStyleable`.
42 |
43 | If you want to customize properties of the transition, such as the jelly factor, pass an instance of `Gagat.Configuration` as the last argument to `Gagat.configure(for:with:using:)`, or omit it if you want to use the defaults.
44 |
45 | **Important:** In order for Gagat to work as expected you _must_ keep a reference to the value returned by `Gagat.configure(for:with:using:)` for the entire lifetime of your application (or until you want to disable Gagat).
46 |
47 | ```swift
48 | // AppDelegate.swift
49 |
50 | var window: UIWindow?
51 | var gagatTransitionHandle: Gagat.TransitionHandle!
52 |
53 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
54 | let configuration = Gagat.Configuration(jellyFactor: 1.5)
55 | let styleableViewController = window!.rootViewController as! GagatStyleable
56 | gagatTransitionHandle = Gagat.configure(for: window!, with: styleableViewController, using: configuration)
57 |
58 | return true
59 | }
60 | ```
61 |
62 | #### You're done!
63 |
64 | You should now be able to switch between your different styles by using a two-finger downwards pan from anywhere in your application.
65 |
66 | ### About Objective-C interoperability
67 |
68 | Using Gagat from Objective-C is fundamentally the same as using it from Swift, but there are some minor differences.
69 |
70 | First, you need to make sure you've added both the `GagatObjectiveC.framework` _and_ the `Gagat.framework` to your project, and that you're importing `GagatObjectiveC` (i.e. `@import GagatObjectiveC` or `#import `).
71 |
72 | Second, the type names are slightly different:
73 |
74 | | Swift Type | Objective-C Type |
75 | | ------------------------ | --------------------- |
76 | | `Gagat` | `GGTManager` |
77 | | `GagatStyleable` | `GGTStyleable` |
78 | | `Gagat.Configuration` | `GGTConfiguration` |
79 | | `Gagat.TransitionHandle` | `GGTTransitionHandle` |
80 |
81 | ## Running the Example app
82 | Gagat includes an app that showcases what this library has to offer. To run the Example app, open [Gagat.xcodeproj](Gagat.xcodeproj) and run the _Gagat Example_ scheme. If you want to run the Example app on a device (you do!) then you'll need to select a team in the target settings for the _Gagat Example_ target.
83 |
84 | #### Podcasts in the Example app
85 | * [If I Were You](http://ifiwereyoushow.com)
86 | * [Radiolab](http://radiolab.org)
87 | * [Appodden](https://overcast.fm/itunes1005587579/appodden)
88 | * [Love + Radio](http://loveandradio.org)
89 | * [Nancy](https://www.wnyc.org/shows/nancy)
90 |
91 | ## Apps that use Gagat
92 | If you're on your iPhone or iPad and want to try Gagat, download one of the following apps. They all use Gagat!
93 |
94 | * [Cascable](https://cascable.se)
95 | * [Push Me](https://pushme.jagcesar.se)
96 | * [Bitbook](https://bitbookapp.com)
97 |
98 | _Want your app to be listed here? Please create a pull request that adds it to the end of the list._
99 |
100 | ## Credits
101 | The Gagat logo was created by [Johan Rothoff Andersson](http://www.johanrothoff.com).
102 |
103 | ## License
104 |
105 | The MIT License (MIT)
106 |
107 | Copyright 2017 Cocoabeans Software
108 |
109 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
110 |
111 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
112 |
113 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
114 |
115 | [Carthage]: https://github.com/Carthage/Carthage
--------------------------------------------------------------------------------
/gagat_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/gagat_example.gif
--------------------------------------------------------------------------------
/gagat_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boerworz/Gagat/2f61038d7eddb156636045c749877e56b1f51b12/gagat_logo.png
--------------------------------------------------------------------------------