├── .DS_Store
├── .gitattributes
├── .gitignore
├── CleanArchitectureWithCoordinatorPatternDemo.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── CleanArchitectureWithCoordinatorPatternDemo.xcworkspace
└── contents.xcworkspacedata
├── CleanArchitectureWithCoordinatorPatternDemo
├── AppCoordinator.swift
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── art1.imageset
│ │ ├── Contents.json
│ │ └── f9714f9bf554ff24b06c978aea9a6a25--marvel-art-marvel-heroes.jpg
│ ├── art2.imageset
│ │ ├── Contents.json
│ │ └── art2.jpg
│ ├── art3.imageset
│ │ ├── Contents.json
│ │ └── art3.jpg
│ ├── background.imageset
│ │ ├── Contents.json
│ │ └── fa252277c39aa2f722fd9d5ce2bfccce--man-wallpaper-ipod-wallpaper.jpg
│ ├── enter.imageset
│ │ ├── Contents.json
│ │ └── enter.jpg
│ └── splash.imageset
│ │ ├── Contents.json
│ │ └── splash.jpg
├── Info.plist
├── Resources
│ └── Storyboards
│ │ ├── Auth.storyboard
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ └── Onboarding.storyboard
└── Source
│ ├── Common
│ ├── Base
│ │ └── BaseCoordinator.swift
│ ├── Bridging-Headers
│ │ └── CommonCrypto-Bridging-Header.h
│ ├── Extensions
│ │ ├── IndexPath+Helper.swift
│ │ ├── NSObject+ClassDefinition.swift
│ │ ├── String+md5.swift
│ │ ├── UIAlertController+Helper.swift
│ │ ├── UICollectionView+Nib.swift
│ │ └── UIViewController+Creation.swift
│ ├── Factories
│ │ ├── Coordinator
│ │ │ ├── CoordinatorFactory.swift
│ │ │ └── CoordinatorFactoryProtocol.swift
│ │ └── Modules
│ │ │ ├── Authorization
│ │ │ └── AuthorizationFactoryProtocol.swift
│ │ │ ├── Main
│ │ │ └── MainFactoryProtocol.swift
│ │ │ ├── ModulesFactory.swift
│ │ │ └── Onboarding
│ │ │ └── OnboardingFactoryProtocol.swift
│ ├── Helpers
│ │ ├── Constants.swift
│ │ ├── RequestWrapper.swift
│ │ ├── Router.swift
│ │ ├── Session.swift
│ │ └── UserDefaultsWrapper.swift
│ ├── Managers
│ │ └── Networking
│ │ │ ├── NSError+Creation.swift
│ │ │ ├── RequestManager.swift
│ │ │ ├── RequestManagerConfiguration.swift
│ │ │ └── RequestManagerErroring.swift
│ ├── Model
│ │ ├── Character.swift
│ │ ├── Comics.swift
│ │ ├── ComicsItem.swift
│ │ ├── Events.swift
│ │ ├── EventsItem.swift
│ │ ├── Series.swift
│ │ ├── SeriesItem.swift
│ │ ├── Stories.swift
│ │ ├── StoriesItem.swift
│ │ ├── Thumbnail.swift
│ │ └── URLS.swift
│ └── Protocols
│ │ ├── BaseViewProtocol.swift
│ │ ├── Coordinatable.swift
│ │ ├── Presentable.swift
│ │ └── Routable.swift
│ └── Modules
│ └── Flows
│ ├── Authorization
│ ├── AuthorizationCoordinator.swift
│ ├── AuthorizationCoordinatorOutput.swift
│ └── Controllers
│ │ ├── Enter
│ │ ├── EnterAssembly.swift
│ │ ├── EnterInteractor.swift
│ │ ├── EnterPresenter.swift
│ │ └── EnterViewController.swift
│ │ ├── EnterAssembly.swift
│ │ ├── EnterInteractor.swift
│ │ ├── EnterPresenter.swift
│ │ ├── EnterViewController.swift
│ │ └── EnterViewProtocol.swift
│ ├── Main
│ ├── Controllers
│ │ ├── Cells
│ │ │ └── CharacterCollectionViewCell.swift
│ │ └── Characters
│ │ │ ├── CharactersAssembly.swift
│ │ │ ├── CharactersDataSource.swift
│ │ │ ├── CharactersInteractor.swift
│ │ │ ├── CharactersPresenter.swift
│ │ │ ├── CharactersViewController.swift
│ │ │ └── CharactersViewProtocol.swift
│ ├── MainCoordinator.swift
│ ├── MainCoordinatorOutput.swift
│ └── MainRequestManager.swift
│ └── Onboarding
│ ├── Controllers
│ ├── OnboardingPageViewController.swift
│ ├── OnboardingViewController.swift
│ └── OnboardingViewProtocol.swift
│ ├── OnboardingCoordinator.swift
│ └── OnboardingCoordinatorOutput.swift
├── LICENSE
├── Module VIP.xctemplate
├── .DS_Store
├── TemplateIcon.icns
├── TemplateInfo.plist
├── ___FILEBASENAME___Assembly.swift
├── ___FILEBASENAME___Interactor.swift
├── ___FILEBASENAME___Presenter.swift
├── ___FILEBASENAME___ViewController.swift
└── ___FILEBASENAME___ViewProtocol.swift
├── Podfile
├── Podfile.lock
├── Pods
├── Alamofire
│ ├── LICENSE
│ ├── README.md
│ └── Source
│ │ ├── AFError.swift
│ │ ├── Alamofire.swift
│ │ ├── DispatchQueue+Alamofire.swift
│ │ ├── MultipartFormData.swift
│ │ ├── NetworkReachabilityManager.swift
│ │ ├── Notifications.swift
│ │ ├── ParameterEncoding.swift
│ │ ├── Request.swift
│ │ ├── Response.swift
│ │ ├── ResponseSerialization.swift
│ │ ├── Result.swift
│ │ ├── ServerTrustPolicy.swift
│ │ ├── SessionDelegate.swift
│ │ ├── SessionManager.swift
│ │ ├── TaskDelegate.swift
│ │ ├── Timeline.swift
│ │ └── Validation.swift
├── AlamofireObjectMapper
│ ├── AlamofireObjectMapper
│ │ └── AlamofireObjectMapper.swift
│ ├── LICENSE
│ └── README.md
├── Kingfisher
│ ├── LICENSE
│ ├── README.md
│ └── Sources
│ │ ├── AnimatedImageView.swift
│ │ ├── Box.swift
│ │ ├── CacheSerializer.swift
│ │ ├── Filter.swift
│ │ ├── FormatIndicatedCacheSerializer.swift
│ │ ├── Image.swift
│ │ ├── ImageCache.swift
│ │ ├── ImageDownloader.swift
│ │ ├── ImagePrefetcher.swift
│ │ ├── ImageProcessor.swift
│ │ ├── ImageTransition.swift
│ │ ├── ImageView+Kingfisher.swift
│ │ ├── Indicator.swift
│ │ ├── Kingfisher.h
│ │ ├── Kingfisher.swift
│ │ ├── KingfisherManager.swift
│ │ ├── KingfisherOptionsInfo.swift
│ │ ├── Placeholder.swift
│ │ ├── RequestModifier.swift
│ │ ├── Resource.swift
│ │ ├── String+MD5.swift
│ │ ├── ThreadHelper.swift
│ │ └── UIButton+Kingfisher.swift
├── Manifest.lock
├── ObjectMapper
│ ├── LICENSE
│ ├── README-CN.md
│ └── Sources
│ │ ├── CustomDateFormatTransform.swift
│ │ ├── DataTransform.swift
│ │ ├── DateFormatterTransform.swift
│ │ ├── DateTransform.swift
│ │ ├── DictionaryTransform.swift
│ │ ├── EnumOperators.swift
│ │ ├── EnumTransform.swift
│ │ ├── FromJSON.swift
│ │ ├── HexColorTransform.swift
│ │ ├── ISO8601DateTransform.swift
│ │ ├── ImmutableMappable.swift
│ │ ├── IntegerOperators.swift
│ │ ├── Map.swift
│ │ ├── MapError.swift
│ │ ├── Mappable.swift
│ │ ├── Mapper.swift
│ │ ├── NSDecimalNumberTransform.swift
│ │ ├── Operators.swift
│ │ ├── ToJSON.swift
│ │ ├── TransformOf.swift
│ │ ├── TransformOperators.swift
│ │ ├── TransformType.swift
│ │ └── URLTransform.swift
├── Pods.xcodeproj
│ └── project.pbxproj
└── Target Support Files
│ ├── Alamofire
│ ├── Alamofire-dummy.m
│ ├── Alamofire-prefix.pch
│ ├── Alamofire-umbrella.h
│ ├── Alamofire.modulemap
│ ├── Alamofire.xcconfig
│ └── Info.plist
│ ├── AlamofireObjectMapper
│ ├── AlamofireObjectMapper-dummy.m
│ ├── AlamofireObjectMapper-prefix.pch
│ ├── AlamofireObjectMapper-umbrella.h
│ ├── AlamofireObjectMapper.modulemap
│ ├── AlamofireObjectMapper.xcconfig
│ └── Info.plist
│ ├── Kingfisher
│ ├── Info.plist
│ ├── Kingfisher-dummy.m
│ ├── Kingfisher-prefix.pch
│ ├── Kingfisher-umbrella.h
│ ├── Kingfisher.modulemap
│ └── Kingfisher.xcconfig
│ ├── ObjectMapper
│ ├── Info.plist
│ ├── ObjectMapper-dummy.m
│ ├── ObjectMapper-prefix.pch
│ ├── ObjectMapper-umbrella.h
│ ├── ObjectMapper.modulemap
│ └── ObjectMapper.xcconfig
│ └── Pods-CleanArchitectureWithCoordinatorPatternDemo
│ ├── Info.plist
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-acknowledgements.markdown
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-acknowledgements.plist
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-dummy.m
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-frameworks.sh
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-resources.sh
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo-umbrella.h
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo.debug.xcconfig
│ ├── Pods-CleanArchitectureWithCoordinatorPatternDemo.modulemap
│ └── Pods-CleanArchitectureWithCoordinatorPatternDemo.release.xcconfig
├── README.md
├── install.swift
└── uninstall.swift
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/.DS_Store
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/AppCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppCoordinator.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 06.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | fileprivate enum LaunchInstructor {
12 | case onboarding, authorization, main
13 |
14 | static func setup() -> LaunchInstructor {
15 | switch (Session.isSeenOnboarding, Session.isAuthorized) {
16 | case (false, false), (true, false):
17 | return .authorization
18 | case (false, true):
19 | return .onboarding
20 | case (true, true):
21 | return .main
22 | }
23 | }
24 | }
25 |
26 | final class AppCoordinator: BaseCoordinator {
27 |
28 | fileprivate let factory: CoordinatorFactoryProtocol
29 | fileprivate let router : Routable
30 |
31 | fileprivate var instructor: LaunchInstructor {
32 | return LaunchInstructor.setup()
33 | }
34 |
35 | init(router: Routable, factory: CoordinatorFactory) {
36 | self.router = router
37 | self.factory = factory
38 | }
39 | }
40 |
41 | // MARK:- Coordinatable
42 | extension AppCoordinator: Coordinatable {
43 | func start() {
44 | switch instructor {
45 | case .authorization:
46 | performAuthorizationFlow()
47 | case .onboarding:
48 | performOnboarding()
49 | case .main:
50 | performMainFlow()
51 | }
52 | }
53 | }
54 |
55 | // MARK:- Private methods
56 | private extension AppCoordinator {
57 | func performAuthorizationFlow() {
58 | let coordinator = factory.makeAuthorizationCoordinator(router: router)
59 | coordinator.finishFlow = { [unowned self, unowned coordinator] in
60 | self.removeDependency(coordinator)
61 | self.start()
62 | }
63 | addDependency(coordinator)
64 | coordinator.start()
65 | }
66 |
67 | func performMainFlow() {
68 | let coordinator = factory.makeMainCoordinator(router: router)
69 | coordinator.finishFlow = { [unowned self, unowned coordinator] in
70 | self.start()
71 | self.removeDependency(coordinator)
72 | }
73 | addDependency(coordinator)
74 | coordinator.start()
75 | }
76 |
77 | func performOnboarding() {
78 | let coordinator = factory.makeOnboardingCoordinator(router: router)
79 | coordinator.finishFlow = { [weak self, weak coordinator] in
80 | guard
81 | let `self` = self,
82 | let `coordinator` = coordinator
83 | else { return }
84 | Session.isSeenOnboarding = true
85 | self.start()
86 | self.removeDependency(coordinator)
87 | }
88 | addDependency(coordinator)
89 | coordinator.start()
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 06.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | var rootController: UINavigationController {
17 | window?.rootViewController = UINavigationController()
18 | return window?.rootViewController as! UINavigationController
19 | }
20 |
21 | fileprivate lazy var coordinator: Coordinatable = self.makeCoordinator()
22 |
23 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
24 | // Override point for customization after application launch.
25 |
26 | coordinator.start()
27 | return true
28 | }
29 | }
30 |
31 | // MARK:- Private methods
32 | private extension AppDelegate {
33 | func makeCoordinator() -> Coordinatable {
34 | return AppCoordinator(router: Router(rootController: rootController),
35 | factory: CoordinatorFactory())
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "f9714f9bf554ff24b06c978aea9a6a25--marvel-art-marvel-heroes.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art1.imageset/f9714f9bf554ff24b06c978aea9a6a25--marvel-art-marvel-heroes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art1.imageset/f9714f9bf554ff24b06c978aea9a6a25--marvel-art-marvel-heroes.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "art2.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art2.imageset/art2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art2.imageset/art2.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "art3.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art3.imageset/art3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/art3.imageset/art3.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/background.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "fa252277c39aa2f722fd9d5ce2bfccce--man-wallpaper-ipod-wallpaper.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/background.imageset/fa252277c39aa2f722fd9d5ce2bfccce--man-wallpaper-ipod-wallpaper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/background.imageset/fa252277c39aa2f722fd9d5ce2bfccce--man-wallpaper-ipod-wallpaper.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/enter.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "enter.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/enter.imageset/enter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/enter.imageset/enter.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/splash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "splash.jpg",
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 | }
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/splash.imageset/splash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/CleanArchitectureWithCoordinatorPatternDemo/Assets.xcassets/splash.imageset/splash.jpg
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | NSAppTransportSecurity
24 |
25 | NSAllowsArbitraryLoads
26 |
27 |
28 | UILaunchStoryboardName
29 | LaunchScreen
30 | UIMainStoryboardFile
31 | Main
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Resources/Storyboards/Auth.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Georgia
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Resources/Storyboards/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Base/BaseCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseCoordinator.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BaseCoordinator {
12 |
13 | var childCoordinators: [Coordinatable] = []
14 |
15 | // Add only unique object
16 |
17 | func addDependency(_ coordinator: Coordinatable) {
18 | for element in childCoordinators {
19 | if element === coordinator { return }
20 | }
21 | childCoordinators.append(coordinator)
22 | }
23 |
24 | func removeDependency(_ coordinator: Coordinatable?) {
25 | guard
26 | childCoordinators.isEmpty == false,
27 | let coordinator = coordinator
28 | else { return }
29 |
30 | for (index, element) in childCoordinators.enumerated() {
31 | if element === coordinator {
32 | childCoordinators.remove(at: index)
33 | break
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Bridging-Headers/CommonCrypto-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // CommonCrypto-Bridging-Header.h
3 | // Marvel
4 | //
5 | // Created by Максим on 05.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | #ifndef CommonCrypto_Bridging_Header_h
10 | #define CommonCrypto_Bridging_Header_h
11 |
12 |
13 | #endif /* CommonCrypto_Bridging_Header_h */
14 |
15 | #import
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Extensions/IndexPath+Helper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IndexPath+Helper.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 28.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension IndexPath {
12 | static func configure(for anyValues: [T], with previusValues: [V], section: Int) -> [IndexPath] {
13 | let from = !previusValues.isEmpty ? previusValues.count - anyValues.count : 0
14 | let newIndexPaths: [IndexPath] = (from...previusValues.count - 1).map { IndexPath(item: $0, section: section) }
15 | return newIndexPaths
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Extensions/NSObject+ClassDefinition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+ClassDefinition.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSObject {
12 | static func nameOfClass() -> String {
13 | return NSStringFromClass(self).components(separatedBy: ".").last!
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Extensions/String+md5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+md5.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 05.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension String {
12 | func md5() -> String! {
13 | let str = self.cString(using: String.Encoding.utf8)
14 | let strLen = CUnsignedInt(self.lengthOfBytes(using: String.Encoding.utf8))
15 | let digestLen = Int(CC_MD5_DIGEST_LENGTH)
16 | let result = UnsafeMutablePointer.allocate(capacity: digestLen)
17 |
18 | CC_MD5(str!, strLen, result)
19 |
20 | let hash = NSMutableString()
21 | for i in 0.. Void)? = nil)
18 | {
19 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
20 |
21 | let alertActionOk = UIAlertAction(title: "OK", style: .default) { action in
22 | alert.dismiss(animated: true, completion: nil)
23 | if let actionBlock = actionBlock {
24 | actionBlock()
25 | }
26 | }
27 |
28 | alert.addAction(alertActionOk)
29 | DispatchQueue.main.async(execute: {
30 | viewController.present(alert, animated: true, completion: nil)
31 | if tintColor != nil {
32 | alert.view.tintColor = tintColor!
33 | }
34 | })
35 | }
36 |
37 | public static func showActionSheet(
38 | title: String?,
39 | message: String?,
40 | viewController: UIViewController,
41 | actions: [UIAlertAction]?,
42 | cancelTitle: String,
43 | tintColor: UIColor?)
44 | {
45 | let alert = UIAlertController(title: title,
46 | message: message,
47 | preferredStyle: UI_USER_INTERFACE_IDIOM() == .pad ? .alert : .actionSheet)
48 | alert.addActions(actions)
49 | let alertActionCancel = UIAlertAction(title: cancelTitle, style: .cancel, handler: nil)
50 | alert.addAction(alertActionCancel)
51 | DispatchQueue.main.async(execute: {
52 | viewController.present(alert, animated: true, completion: nil)
53 | if tintColor != nil {
54 | alert.view.tintColor = tintColor!
55 | }
56 | })
57 | }
58 |
59 | func addAction(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)?) {
60 | let action = UIAlertAction(title: title, style: style, handler: handler)
61 | addAction(action)
62 | }
63 |
64 | func addCancelAction(title: String?) {
65 | let action = UIAlertAction(title: title, style: .cancel, handler: nil)
66 | addAction(action)
67 | }
68 | }
69 |
70 | // MARK:- Add methods
71 | public extension UIAlertController {
72 | public func addActions(_ actions: [UIAlertAction]?) {
73 | actions?.forEach { self.addAction($0) }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Extensions/UICollectionView+Nib.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionView+Nib.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UICollectionView {
12 | func registerNib(_ cellType: T.Type) {
13 | let className = String(describing: cellType)
14 | let nib = UINib(nibName: className, bundle: nil)
15 | let identifier = className + "ID"
16 | register(nib, forCellWithReuseIdentifier: identifier)
17 | }
18 |
19 | func registerNibForSupplementaryViewOfKind(_ cellType: T.Type, kind: String) {
20 | let className = String(describing: cellType)
21 | let nib = UINib(nibName: className, bundle: nil)
22 | let identifier = className + "ID"
23 | register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
24 | }
25 |
26 | func dequeueReusableCell(_ cellType: T.Type, indexPath: IndexPath) -> T {
27 | let className = String(describing: cellType)
28 | let identifier = className + "ID"
29 | return dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! T
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Extensions/UIViewController+Creation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Creation.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIViewController {
12 | static func controllerInStoryboard(_ storyboard: UIStoryboard, identifier: String) -> Self {
13 | return instantiateControllerInStoryboard(storyboard, identifier: identifier)
14 | }
15 |
16 | static func controllerInStoryboard(_ storyboard: UIStoryboard) -> Self {
17 | return controllerInStoryboard(storyboard, identifier: nameOfClass())
18 | }
19 |
20 | static func controllerFromStoryboard(_ storyboard: Storyboards) -> Self {
21 | return controllerInStoryboard(UIStoryboard(name: storyboard.rawValue, bundle: nil), identifier: nameOfClass())
22 | }
23 | }
24 |
25 | private extension UIViewController {
26 | static func instantiateControllerInStoryboard(_ storyboard: UIStoryboard, identifier: String) -> T {
27 | return storyboard.instantiateViewController(withIdentifier: identifier) as! T
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Coordinator/CoordinatorFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoordinatorFactory.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class CoordinatorFactory {
12 | fileprivate let modulesFactory = ModulesFactory()
13 | }
14 |
15 | // MARK:- CoordinatorFactoryProtocol
16 | extension CoordinatorFactory: CoordinatorFactoryProtocol {
17 | func makeOnboardingCoordinator(router: Routable) -> Coordinatable & OnboardingCoordinatorOutput {
18 | return OnboardingCoordinator(with: modulesFactory, router: router)
19 | }
20 |
21 | func makeAuthorizationCoordinator(router: Routable) -> AuthorizationCoordinatorOutput & Coordinatable {
22 | return AuthorizationCoordinator(with: modulesFactory, router: router)
23 | }
24 |
25 | func makeMainCoordinator(router: Routable) -> Coordinatable & MainCoordinatorOutput {
26 | return MainCoordinator(with: modulesFactory, router: router)
27 | }
28 | }
29 |
30 | // MARK:- Private methods
31 | private extension CoordinatorFactory {
32 | func router(_ navController: UINavigationController?, in storyboard: Storyboards) -> Routable {
33 | return Router(rootController: navigationController(navController, in: storyboard))
34 | }
35 |
36 | func navigationController(_ navController: UINavigationController?, in storyboard: Storyboards) -> UINavigationController {
37 | return navController == nil ? UINavigationController.controllerFromStoryboard(storyboard) : navController!
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Coordinator/CoordinatorFactoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoordinatorFactoryProtocol.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol CoordinatorFactoryProtocol {
12 | func makeOnboardingCoordinator(router: Routable) -> Coordinatable & OnboardingCoordinatorOutput
13 | func makeAuthorizationCoordinator(router: Routable) -> Coordinatable & AuthorizationCoordinatorOutput
14 | func makeMainCoordinator(router: Routable) -> Coordinatable & MainCoordinatorOutput
15 | }
16 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Modules/Authorization/AuthorizationFactoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationFactory.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AuthorizationFactoryProtocol {
12 | func makeEnterView() -> EnterViewProtocol
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Modules/Main/MainFactoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainFactoryProtocol.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol MainFactoryProtocol {
12 | func makeCharatersView() -> CharactersViewProtocol
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Modules/ModulesFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModulesFactory.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ModulesFactory {}
12 |
13 | // MARK:- AuthorizationFactoryProtocol
14 | extension ModulesFactory: AuthorizationFactoryProtocol {
15 | func makeEnterView() -> EnterViewProtocol {
16 | let view: EnterViewController = EnterViewController.controllerFromStoryboard(.authorization)
17 | EnterAssembly.assembly(with: view)
18 | return view
19 | }
20 | }
21 |
22 | // MARK:- OnboardingFactoryProtocol
23 | extension ModulesFactory: OnboardingFactoryProtocol {
24 | func makeOnboardingView() -> OnboardingViewProtocol {
25 | let view: OnboardingPageViewController = OnboardingPageViewController.controllerFromStoryboard(.onboarding)
26 | return view
27 | }
28 | }
29 |
30 | // MARK:- MainFactoryProtocol
31 | extension ModulesFactory: MainFactoryProtocol {
32 | func makeCharatersView() -> CharactersViewProtocol {
33 | let view: CharactersViewController = CharactersViewController.controllerFromStoryboard(.main)
34 | CharactersAssembly.assembly(with: view)
35 | return view
36 | }
37 | }
38 |
39 | // MARK:- Private methods
40 | private extension ModulesFactory {
41 | func router(_ navController: UINavigationController?, in storyboard: Storyboards) -> Routable {
42 | return Router(rootController: navigationController(navController, in: storyboard))
43 | }
44 |
45 | func navigationController(_ navController: UINavigationController?, in storyboard: Storyboards) -> UINavigationController {
46 | return navController == nil ? UINavigationController.controllerFromStoryboard(storyboard) : navController!
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Factories/Modules/Onboarding/OnboardingFactoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingFactoryProtocol.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 06.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol OnboardingFactoryProtocol {
12 | func makeOnboardingView() -> OnboardingViewProtocol
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Helpers/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK:- Typealiases
12 | typealias CompletionBlock = () -> Void
13 | typealias AlertCompletionBlock = (String) -> Void
14 |
15 | // MARK:- Storyboards enum
16 | enum Storyboards: String {
17 |
18 | case authorization = "Auth"
19 | case main = "Main"
20 | case onboarding = "Onboarding"
21 |
22 | }
23 |
24 | // MARK:- PersistantKeys enum
25 | enum PersistantKeys {
26 |
27 | static let isSeenOnboarding = "kIsSeenOnboarding"
28 | static let token = "kToken"
29 |
30 | }
31 |
32 | enum Urls {
33 | static let base = "http://gateway.marvel.com"
34 |
35 | enum Endpoints {
36 | static let characters = "/v1/public/characters"
37 | }
38 |
39 | static let timestamp: NSNumber = 1
40 | }
41 |
42 | enum ApiKeys {
43 | static let publicKey = "44c6606f72114e4a9eaf84cb93fb8863"
44 | static let privateKey = "a92b6b3b8140846adf4eeebb64d576b5570be727"
45 | }
46 |
47 | // MARK:- Erroring
48 | enum ErrorCode: Int {
49 | case nilResponse = -11
50 | case emptyResponse = -10
51 | case undefined = -1
52 | }
53 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Helpers/RequestWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GoogleMapsRequestWrapper.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 23.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Alamofire
11 | import ObjectMapper
12 |
13 | public class RequestWrapper {
14 |
15 | let requestManager: RequestManager
16 |
17 | init(with configuration: RequestManagerConfiguration) {
18 | requestManager = RequestManager(configuration: configuration)
19 | }
20 |
21 | open func makeRequestWithoutMapping(
22 | URL: String,
23 | method: HTTPMethod = .post,
24 | encoding: ParameterEncoding? = nil,
25 | parameters: Parameters? = nil,
26 | headers: Headers? = nil,
27 | failure: @escaping Failure,
28 | success: @escaping Success)
29 | {
30 | requestManager.makeRequestWithoutMapping(URL: URL,
31 | method: method,
32 | encoding: encoding,
33 | parameters: parameters,
34 | headers: configureHeaders(headers),
35 | failure: failure,
36 | success: success)
37 | }
38 |
39 | open func makeRequestObject(
40 | URL: String,
41 | method: HTTPMethod = .post,
42 | encoding: ParameterEncoding? = nil,
43 | parameters: Parameters? = nil,
44 | headers: Headers? = nil,
45 | keyPath: String,
46 | failure: @escaping Failure,
47 | success: @escaping Success,
48 | successNoMapping: SuccessNoMapping? = nil,
49 | responseHeaders: ResponseHeaders? = nil)
50 | {
51 | requestManager.makeRequestObject(URL: URL,
52 | method: method,
53 | encoding: encoding,
54 | parameters: parameters,
55 | headers: configureHeaders(headers),
56 | keyPath: keyPath,
57 | failure: failure,
58 | success: success,
59 | successNoMapping: successNoMapping,
60 | successHeaders: responseHeaders)
61 | }
62 |
63 | open func makeRequest(
64 | URL: String,
65 | method: HTTPMethod = .post,
66 | encoding: ParameterEncoding? = nil,
67 | parameters: Parameters? = nil,
68 | headers: Headers? = nil,
69 | keyPath: String,
70 | failure: @escaping Failure,
71 | success: @escaping Success<[T]>,
72 | successNoMapping: SuccessNoMapping? = nil)
73 | {
74 | requestManager.makeRequest(URL: URL,
75 | method: method,
76 | encoding: encoding,
77 | parameters: parameters,
78 | headers: configureHeaders(headers),
79 | keyPath: keyPath,
80 | failure: failure,
81 | success: success)
82 | }
83 | }
84 |
85 | extension RequestWrapper {
86 | func configureHeaders(_ headers: Headers? = nil) -> Headers {
87 | var _headers: Headers = [:]
88 | if let headers = headers {
89 | _headers += headers
90 | }
91 | return _headers
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Helpers/Router.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Router.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | typealias RouterCompletions = [UIViewController : CompletionBlock]
12 |
13 | final class Router: NSObject {
14 |
15 | // MARK:- Private variables
16 | fileprivate weak var rootController: UINavigationController?
17 |
18 | fileprivate var completions: RouterCompletions
19 |
20 | init(rootController: UINavigationController) {
21 | self.rootController = rootController
22 | completions = [:]
23 | }
24 |
25 | var toPresent: UIViewController? {
26 | return rootController
27 | }
28 | }
29 |
30 | // MARK:- Private methods
31 | private extension Router {
32 | func runCompletion(for controller: UIViewController) {
33 | guard let completion = completions[controller] else { return }
34 | completion()
35 | completions.removeValue(forKey: controller)
36 | }
37 | }
38 |
39 | // MARK:- Routable
40 | extension Router: Routable {
41 | func present(_ module: Presentable?) {
42 | present(module, animated: true)
43 | }
44 |
45 | func present(_ module: Presentable?, animated: Bool) {
46 | guard let controller = module?.toPresent else { return }
47 | rootController?.present(controller, animated: animated, completion: nil)
48 | }
49 |
50 | func push(_ module: Presentable?) {
51 | push(module, animated: true)
52 | }
53 |
54 | func push(_ module: Presentable?, animated: Bool) {
55 | push(module, animated: animated, completion: nil)
56 | }
57 |
58 | func push(_ module: Presentable?, animated: Bool, completion: CompletionBlock?) {
59 | guard
60 | let controller = module?.toPresent,
61 | !(controller is UINavigationController)
62 | else { assertionFailure("⚠️Deprecated push UINavigationController."); return }
63 |
64 | if let completion = completion {
65 | completions[controller] = completion
66 | }
67 | rootController?.pushViewController(controller, animated: animated)
68 | }
69 |
70 | func popModule() {
71 | popModule(animated: true)
72 | }
73 |
74 | func popModule(animated: Bool) {
75 | if let controller = rootController?.popViewController(animated: animated) {
76 | runCompletion(for: controller)
77 | }
78 | }
79 |
80 | func dismissModule() {
81 | dismissModule(animated: true, completion: nil)
82 | }
83 |
84 | func dismissModule(animated: Bool, completion: CompletionBlock?) {
85 | rootController?.dismiss(animated: animated, completion: completion)
86 | }
87 |
88 | func setRootModule(_ module: Presentable?) {
89 | setRootModule(module, hideBar: false)
90 | }
91 |
92 | func setRootModule(_ module: Presentable?, hideBar: Bool) {
93 | guard let controller = module?.toPresent else { return }
94 | rootController?.setViewControllers([controller], animated: false)
95 | rootController?.isNavigationBarHidden = hideBar
96 | }
97 |
98 | func popToRootModule(animated: Bool) {
99 | if let controllers = rootController?.popToRootViewController(animated: animated) {
100 | controllers.forEach { controller in
101 | runCompletion(for: controller)
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Helpers/Session.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Session.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | typealias Credentials = (username: String, password: String)
12 |
13 | struct Session {
14 | static var isAuthorized: Bool {
15 | return UserDefaultsWrapper.token != nil
16 | }
17 |
18 | static var isSeenOnboarding: Bool {
19 | get {
20 | return UserDefaultsWrapper.isSeenOnboarding
21 | }
22 | set {
23 | UserDefaultsWrapper.isSeenOnboarding = newValue
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Helpers/UserDefaultsWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDefaultsWrapper.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UserDefaultsWrapper {
12 |
13 | fileprivate static let UserDefaultsStandart = UserDefaults.standard
14 |
15 | static var isSeenOnboarding: Bool {
16 | get {
17 | return UserDefaultsStandart.bool(forKey: PersistantKeys.isSeenOnboarding)
18 | }
19 | set {
20 | UserDefaultsStandart.set(newValue, forKey: PersistantKeys.isSeenOnboarding)
21 | UserDefaultsStandart.synchronize()
22 | }
23 | }
24 |
25 | static var token: String? {
26 | get {
27 | return UserDefaultsStandart.string(forKey: PersistantKeys.token)
28 | }
29 | set {
30 | UserDefaultsStandart.set(newValue, forKey: PersistantKeys.token)
31 | UserDefaultsStandart.synchronize()
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Managers/Networking/NSError+Creation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSError+Creation.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 23.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension NSError {
12 |
13 | public static func error(title: String, code: Int) -> NSError {
14 | let bundleName = Bundle.main.bundleIdentifier!
15 | return NSError(domain: bundleName, code: code, userInfo: [NSLocalizedDescriptionKey : title])
16 | }
17 |
18 | public static func error(title: String) -> NSError {
19 | return error(title: title, code: 0)
20 | }
21 | }
22 |
23 | extension NSError {
24 | static func error(title: String, code: ErrorCode) -> NSError {
25 | return NSError.error(title: title, code: code.rawValue)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Managers/Networking/RequestManagerConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestManagerConfiguration.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 23.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 | import Alamofire
12 |
13 | public typealias ErrorMapping = (Any) -> (RequestManagerErroring?)
14 | public typealias HttpErrorHandler = (Int?) -> Void
15 |
16 | public struct RequestManagerConfiguration {
17 | public var baseURL: String
18 |
19 | public var defaultParams : Parameters?
20 | public var defaultHeaders : Headers?
21 | public var timeout : TimeInterval = 10
22 | public var logging : Bool = false
23 | public var errorMap : ErrorMapping?
24 | public var undefinedError : NSError
25 | public var nilResponseError : NSError
26 | public var encoding : ParameterEncoding
27 | public var httpErrorHandler : HttpErrorHandler?
28 |
29 | public init(baseURL : String,
30 | params : Parameters? = nil,
31 | headers : Headers? = nil,
32 | timeout : TimeInterval = 10,
33 | encoding : ParameterEncoding = URLEncoding.default,
34 | logging : Bool = false,
35 | nilResponseError : NSError = .error(title : "Check your internet connection", code : -11),
36 | undefinedError : NSError = .error(title : "Sorry, but something went wrong", code : -1),
37 | httpErrorHanlder : HttpErrorHandler? = nil,
38 | errorMap : ErrorMapping? = nil)
39 | {
40 | self.baseURL = baseURL
41 | self.defaultParams = params
42 | self.defaultHeaders = headers
43 | self.timeout = timeout
44 | self.encoding = encoding
45 | self.logging = logging
46 | self.undefinedError = undefinedError
47 | self.nilResponseError = nilResponseError
48 | self.errorMap = errorMap
49 | self.httpErrorHandler = httpErrorHanlder
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Managers/Networking/RequestManagerErroring.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestManagerErroring.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 23.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | public protocol RequestManagerErrorMapping: Mappable {
13 | var code : Int? { get set }
14 | var message : String? { get set }
15 | }
16 |
17 | public protocol RequestManagerErroring {
18 | var description: String? { get }
19 | var errorCode: Int { get }
20 | func defaultError() -> Self
21 | func description(code: Int) -> String?
22 | }
23 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Character.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Character.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Character {
13 |
14 | var uid : Int?
15 | var name = ""
16 | var desc = ""
17 | var modified = ""
18 | var resourceURI = ""
19 | var comics : Comics?
20 | var events : Events?
21 | var image : Thumbnail?
22 | var series : Series?
23 | var stories : Stories?
24 | var urls : [URLS]?
25 | }
26 |
27 | // MARK:-
28 | extension Character: Mappable {
29 |
30 | mutating func mapping(map: Map) {
31 | uid <- map["id"]
32 | name <- map["name"]
33 | desc <- map["description"]
34 | modified <- map["modified"]
35 | resourceURI <- map["resourceURI"]
36 | comics <- map["comics"]
37 | events <- map["events"]
38 | image <- map["thumbnail"]
39 | series <- map["series"]
40 | stories <- map["stories"]
41 | urls <- map["urls"]
42 | }
43 |
44 | init?(map: Map) {}
45 |
46 | }
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Comics.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Comics.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Comics {
13 |
14 | var available : Int?
15 | var collectionURI = ""
16 | var comicsItems : [ComicsItem]?
17 | }
18 |
19 | // MARK:- BaseMappable
20 | extension Comics: Mappable {
21 |
22 | mutating func mapping(map: Map) {
23 | available <- map["available"]
24 | collectionURI <- map["collectionURI"]
25 | comicsItems <- map["items"]
26 | }
27 |
28 | init?(map: Map) {}
29 |
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/ComicsItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ComicsItem.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct ComicsItem {
13 |
14 | var name = ""
15 | var resourceURI = ""
16 |
17 | }
18 |
19 | extension ComicsItem: Mappable {
20 |
21 | mutating func mapping(map: Map) {
22 | name <- map["name"]
23 | resourceURI <- map["resourceURI"]
24 | }
25 |
26 | init?(map: Map) {}
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Events.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Events.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Events {
13 |
14 | var available : Int?
15 | var collectionURI = ""
16 | var eventsItems : [EventsItem]?
17 |
18 | }
19 |
20 | // MARK:- BaseMappable
21 | extension Events: Mappable {
22 |
23 | mutating func mapping(map: Map) {
24 | available <- map["available"]
25 | collectionURI <- map["collectionURI"]
26 | eventsItems <- map["items"]
27 | }
28 |
29 | init?(map: Map) {}
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/EventsItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventsItem.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct EventsItem {
13 |
14 | var name = ""
15 | var resourceURI = ""
16 | }
17 |
18 | // MARK:- BaseMappable
19 | extension EventsItem: Mappable {
20 |
21 | mutating func mapping(map: Map) {
22 | name <- map["name"]
23 | resourceURI <- map["resourceURI"]
24 | }
25 |
26 | init?(map: Map) {}
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Series.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Series.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Series {
13 |
14 | var available : Int?
15 | var collectionURI = ""
16 | var seriesItems : [SeriesItem]?
17 |
18 | }
19 |
20 | // MARK:- BaseMappable
21 | extension Series: Mappable {
22 |
23 | mutating func mapping(map: Map) {
24 | available <- map["available"]
25 | collectionURI <- map["collectionURI"]
26 | seriesItems <- map["items"]
27 | }
28 |
29 | init?(map: Map) {}
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/SeriesItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SeriesItem.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct SeriesItem {
13 |
14 | var name = ""
15 | var resourceURI = ""
16 |
17 | }
18 |
19 | // MARK:- BaseMappable
20 | extension SeriesItem: Mappable {
21 |
22 | mutating func mapping(map: Map) {
23 | name <- map["name"]
24 | resourceURI <- map["resourceURI"]
25 | }
26 |
27 | init?(map: Map) {}
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Stories.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Stories.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Stories {
13 |
14 | var available : Int?
15 | var collectionURI = ""
16 | var storiesItems : [StoriesItem]?
17 | }
18 |
19 | // MARK:- BaseMappable
20 | extension Stories: Mappable {
21 |
22 | mutating func mapping(map: Map) {
23 | available <- map["available"]
24 | collectionURI <- map["collectionURI"]
25 | storiesItems <- map["items"]
26 | }
27 |
28 | init?(map: Map) {}
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/StoriesItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StoriesIrem.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct StoriesItem {
13 |
14 | var name = ""
15 | var resourceURI = ""
16 | var type = ""
17 |
18 | }
19 |
20 | // MARK:- BaseMappable
21 | extension StoriesItem: Mappable {
22 |
23 | mutating func mapping(map: Map) {
24 | name <- map["name"]
25 | resourceURI <- map["resourceURI"]
26 | type <- map["type"]
27 | }
28 |
29 | init?(map: Map) {}
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/Thumbnail.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Thumbnail.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct Thumbnail {
13 |
14 | var path = ""
15 | var ext = ""
16 |
17 | }
18 |
19 | // MARK:- BaseMappable
20 | extension Thumbnail: Mappable {
21 |
22 | mutating func mapping(map: Map) {
23 | path <- map["path"]
24 | ext <- map["extension"]
25 | }
26 |
27 | init?(map: Map) {}
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Model/URLS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLS.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 06.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ObjectMapper
11 |
12 | struct URLS {
13 |
14 | var type = ""
15 | var url = ""
16 | }
17 |
18 | // MARK:- BaseMappable
19 | extension URLS: Mappable {
20 |
21 | mutating func mapping(map: Map) {
22 | type <- map["type"]
23 | url <- map["url"]
24 | }
25 |
26 | init?(map: Map) {}
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Protocols/BaseViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewProtocol.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol BaseViewProtocol: NSObjectProtocol, Presentable {}
12 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Protocols/Coordinatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Coordinatable.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol Coordinatable: class {
12 | func start()
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Protocols/Presentable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Presentable.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol Presentable {
12 | var toPresent: UIViewController? { get }
13 | }
14 |
15 | extension UIViewController: Presentable {
16 | var toPresent: UIViewController? {
17 | return self
18 | }
19 |
20 | func showAlert(title: String, message: String? = nil) {
21 | UIAlertController.showAlert(title : title,
22 | message : message,
23 | inViewController : self,
24 | actionBlock : nil)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Common/Protocols/Routable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Routable.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 16.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol Routable: Presentable {
12 |
13 | func present(_ module: Presentable?)
14 | func present(_ module: Presentable?, animated: Bool)
15 |
16 | func push(_ module: Presentable?)
17 | func push(_ module: Presentable?, animated: Bool)
18 | func push(_ module: Presentable?, animated: Bool, completion: CompletionBlock?)
19 |
20 | func popModule()
21 | func popModule(animated: Bool)
22 |
23 | func dismissModule()
24 | func dismissModule(animated: Bool, completion: CompletionBlock?)
25 |
26 | func setRootModule(_ module: Presentable?)
27 | func setRootModule(_ module: Presentable?, hideBar: Bool)
28 |
29 | func popToRootModule(animated: Bool)
30 | }
31 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/AuthorizationCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationCoordinator.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class AuthorizationCoordinator: BaseCoordinator, AuthorizationCoordinatorOutput {
12 |
13 | var finishFlow: CompletionBlock?
14 |
15 | fileprivate let factory: AuthorizationFactoryProtocol
16 | fileprivate let router : Routable
17 |
18 | init(with factory: AuthorizationFactoryProtocol, router: Routable) {
19 | self.factory = factory
20 | self.router = router
21 | }
22 | }
23 |
24 | // MARK:- Coordinatable
25 | extension AuthorizationCoordinator: Coordinatable {
26 | func start() {
27 | performFlow()
28 | }
29 | }
30 |
31 | // MARK:- Private methods
32 | private extension AuthorizationCoordinator {
33 | func performFlow() {
34 | let view = factory.makeEnterView()
35 | view.onCompletion = finishFlow
36 | router.setRootModule(view, hideBar: true)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/AuthorizationCoordinatorOutput.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationCoordinatorOutput.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AuthorizationCoordinatorOutput: class {
12 | var finishFlow: CompletionBlock? { get set }
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/Enter/EnterAssembly.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterAssembly.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 10.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EnterAssemblable: EnterViewProtocol, EnterPresenterOutput {}
12 |
13 | final class EnterAssembly {
14 | static func assembly(with output: EnterPresenterOutput) {
15 | let interactor = EnterPresenter()
16 | let presenter = EnterInteractor()
17 |
18 | interactor.presenter = presenter
19 | presenter.interactor = interactor
20 | presenter.output = output
21 | output.presenter = presenter
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/Enter/EnterInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterInteractor.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 10.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class EnterInteractor {
12 |
13 | weak var presenter: EnterPresenter?
14 | }
15 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/Enter/EnterPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterPresenter.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 10.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EnterPresenterInput: class {
12 |
13 | }
14 |
15 | protocol EnterPresenterOutput: class {
16 | var interactor: EnterPresenterInput? { get set }
17 | }
18 |
19 | final class EnterPresenter {
20 |
21 | weak var output: EnterPresenterOutput?
22 |
23 | var interactor: EnterInteractor?
24 | }
25 |
26 | extension EnterPresenter: EnterPresenterInput {
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/Enter/EnterViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterViewController.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 10.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class EnterViewController: UIViewController, EnterAssemblable {
12 |
13 | var presenter: EnterPresenter?
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/EnterAssembly.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterAssembly.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EnterAssemblable: EnterViewProtocol, EnterPresenterOutput {}
12 |
13 | final class EnterAssembly {
14 | static func assembly(with output: EnterPresenterOutput) {
15 | let interactor = EnterInteractor()
16 | let presenter = EnterPresenter()
17 |
18 | interactor.presenter = presenter
19 | presenter.interactor = interactor
20 | presenter.output = output
21 | output.presenter = presenter
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/EnterInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterInteractor.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class EnterInteractor {
12 |
13 | weak var presenter: EnterPresenter?
14 |
15 | func signIn() {
16 | UserDefaultsWrapper.token = "Some token"
17 | presenter?.handleSuccessSignIn()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/EnterPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterPresenter.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EnterPresenterInput: class {
12 | func onSignIn()
13 | }
14 |
15 | protocol EnterPresenterOutput: class {
16 | var presenter: EnterPresenterInput? { get set }
17 |
18 | func signInProceed()
19 | }
20 |
21 | final class EnterPresenter {
22 |
23 | weak var output: EnterPresenterOutput?
24 |
25 | var interactor: EnterInteractor?
26 |
27 | func handleSuccessSignIn() {
28 | output?.signInProceed()
29 | }
30 | }
31 |
32 | // MARK:- EnterPresenterInput
33 | extension EnterPresenter: EnterPresenterInput {
34 | func onSignIn() {
35 | interactor?.signIn()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/EnterViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterViewController.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class EnterViewController: UIViewController, EnterAssemblable {
12 |
13 | var presenter: EnterPresenterInput?
14 |
15 | var onCompletion: CompletionBlock?
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | }
20 |
21 | @IBAction func signInPressed(_ sender: UIButton) {
22 | presenter?.onSignIn()
23 | }
24 | }
25 |
26 | // MARK:- EnterPresenterOutput
27 | extension EnterViewController {
28 | func signInProceed() {
29 | onCompletion?()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Authorization/Controllers/EnterViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnterViewProtocol.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EnterViewProtocol: BaseViewProtocol {
12 | var onCompletion: CompletionBlock? { get set }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Cells/CharacterCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharacterCVCC.swift
3 | // Marvel
4 | //
5 | // Created by Максим on 08.09.16.
6 | // Copyright © 2016 Максим. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Kingfisher
11 |
12 | class CharacterCollectionViewCell: UICollectionViewCell {
13 |
14 | var character : Character? {
15 | didSet {
16 | guard let character = character else { return }
17 | updateUI(with: character)
18 | }
19 | }
20 |
21 | fileprivate var imageView = UIImageView()
22 |
23 | // MARK: - Private
24 | @IBOutlet fileprivate weak var characterImageView: UIImageView!
25 |
26 | @IBOutlet fileprivate weak var characterNameLabel: UILabel!
27 |
28 | @IBOutlet fileprivate weak var textView: UIView!
29 |
30 | override func layoutSubviews() {
31 | super.layoutSubviews()
32 | layer.cornerRadius = 60.0
33 | clipsToBounds = true
34 | }
35 | }
36 |
37 | // MARK:- Private methods
38 | private extension CharacterCollectionViewCell {
39 | func updateUI(with character: Character) {
40 | characterNameLabel.text = character.name
41 | characterNameLabel.alpha = 0.0
42 | guard
43 | let imageURL = character.image?.path,
44 | let imageExtension = character.image?.ext,
45 | let resource = URL(string: imageURL + "/portrait_uncanny." + imageExtension)
46 | else { return }
47 | characterImageView.kf.setImage(with: resource,
48 | placeholder: nil,
49 | options: nil,
50 | progressBlock: nil) { [weak self] (image, _, _, _) in
51 | self?.characterNameLabel.alpha = 1.0
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersAssembly.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersAssembly.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol CharactersAssemblable: CharactersViewProtocol, CharactersPresenterOutput {}
12 |
13 | final class CharactersAssembly {
14 | static func assembly(with output: CharactersPresenterOutput) {
15 | let interactor = CharactersInteractor()
16 | let presenter = CharactersPresenter()
17 |
18 | interactor.presenter = presenter
19 | presenter.interactor = interactor
20 | presenter.output = output
21 | output.presenter = presenter
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersDataSource.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol CharactersDataSourceDelegate: class {
12 | var collectionView: UICollectionView! { get }
13 | var index: Int! { get set }
14 | }
15 |
16 | final class CharactersDataSource: NSObject {
17 |
18 | lazy var characters: [Character] = []
19 |
20 | weak var delegate: CharactersDataSourceDelegate?
21 | }
22 |
23 | // MARK:- UICollectionViewDataSource
24 | extension CharactersDataSource: UICollectionViewDataSource {
25 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
26 | return characters.count
27 | }
28 |
29 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
30 | let cell = collectionView.dequeueReusableCell(CharacterCollectionViewCell.self, indexPath: indexPath)
31 | cell.character = characters[indexPath.item]
32 | return cell
33 | }
34 | }
35 |
36 | // MARK:- UIScrollViewDelegate
37 | extension CharactersDataSource : UIScrollViewDelegate {
38 |
39 | func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) {
40 |
41 | let layout = delegate?.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
42 |
43 | let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing
44 |
45 | var offset = targetContentOffset.pointee
46 |
47 | let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
48 |
49 | let roundedIndex = round(index)
50 |
51 | offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
52 | targetContentOffset.pointee = offset
53 | }
54 |
55 |
56 | func scrollViewDidScroll(_ scrollView: UIScrollView) {
57 |
58 | guard let delegate = delegate else { return }
59 |
60 | let layout = delegate.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
61 |
62 | let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing
63 |
64 | let offset = scrollView.contentOffset
65 |
66 | let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
67 |
68 | let roundedIndex = round(index)
69 | if Int(roundedIndex) > delegate.index || Int(roundedIndex) < delegate.index {
70 | delegate.index = Int(roundedIndex)
71 | }
72 | }
73 | }
74 |
75 | // MARK:- UICollectionViewDelegate
76 | extension CharactersDataSource: UICollectionViewDelegate {}
77 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersInteractor.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class CharactersInteractor {
12 |
13 | weak var presenter: CharactersPresenter?
14 |
15 | fileprivate let mainReqeustManager = MainRequestManager()
16 |
17 | func getCharacters(by offset: Int, count: Int) {
18 | mainReqeustManager.getCharacters(offset: offset,
19 | count: count,
20 | failure: { (_) in
21 | // TODO:- show alert?
22 | }) { [weak self] (result: [Character]) in
23 | guard let `self` = self else { return }
24 | self.presenter?.received(characters: result)
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersPresenter.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol CharactersPresenterInput: class {
12 | func getCharacters(by offset: Int, count: Int)
13 | }
14 |
15 | protocol CharactersPresenterOutput: class {
16 | var presenter: CharactersPresenterInput? { get set }
17 |
18 | func showActivity()
19 | func hideActivity()
20 |
21 | func received(characters: [Character])
22 | }
23 |
24 | final class CharactersPresenter {
25 |
26 | weak var output: CharactersPresenterOutput?
27 |
28 | var interactor: CharactersInteractor?
29 |
30 | func received(characters: [Character]) {
31 | output?.hideActivity()
32 | output?.received(characters: characters)
33 | }
34 | }
35 |
36 | // MARK:- CharactersPresenterInput
37 | extension CharactersPresenter: CharactersPresenterInput {
38 | func getCharacters(by offset: Int, count: Int) {
39 | output?.showActivity()
40 | interactor?.getCharacters(by: offset, count: count)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersViewController.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class CharactersViewController: UIViewController, CharactersAssemblable, CharactersDataSourceDelegate {
12 |
13 | var presenter: CharactersPresenterInput?
14 |
15 | @IBOutlet fileprivate weak var backgroundImageView : UIImageView!
16 |
17 | @IBOutlet fileprivate weak var loadCharactersIndicatorView : UIActivityIndicatorView!
18 | @IBOutlet fileprivate weak var activityIndicatorView : UIActivityIndicatorView!
19 |
20 | @IBOutlet weak var collectionView : UICollectionView!
21 |
22 | fileprivate var dataSource = CharactersDataSource()
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 | setup()
27 | activityIndicatorView.startAnimating()
28 | presenter?.getCharacters(by: offset, count: count)
29 | }
30 |
31 | fileprivate let count: Int = 3
32 |
33 | fileprivate var offset : Int = 0 {
34 | didSet {
35 | presenter?.getCharacters(by: self.offset, count: self.count)
36 | }
37 | }
38 |
39 | var index : Int! = 0 {
40 | didSet {
41 | if index >= dataSource.characters.count - 3 {
42 | offset += 3
43 | }
44 | }
45 | }
46 | }
47 |
48 | // MARK:- Private methods
49 | private extension CharactersViewController {
50 | func setup() {
51 | setupCollectionView()
52 | }
53 |
54 | func setupCollectionView() {
55 | collectionView.dataSource = dataSource
56 | collectionView.delegate = dataSource
57 |
58 | dataSource.delegate = self
59 | }
60 | }
61 |
62 | // MARK:- CharactersPresenterOutput
63 | extension CharactersViewController {
64 | func showActivity() {
65 | dataSource.characters.isEmpty ? activityIndicatorView.startAnimating() : loadCharactersIndicatorView.startAnimating()
66 | }
67 |
68 | func hideActivity() {
69 | dataSource.characters.isEmpty ? activityIndicatorView.stopAnimating() : loadCharactersIndicatorView.stopAnimating()
70 | }
71 |
72 | func received(characters: [Character]) {
73 | dataSource.characters.append(contentsOf: characters)
74 | let newIndexPaths = IndexPath.configure(for: characters,
75 | with: dataSource.characters,
76 | section: 0)
77 | collectionView.insertItems(at: newIndexPaths)
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/Controllers/Characters/CharactersViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CharactersViewProtocol.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol CharactersViewProtocol: BaseViewProtocol {
12 |
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/MainCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainCoordinator.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class MainCoordinator: BaseCoordinator, MainCoordinatorOutput {
12 |
13 | var finishFlow: CompletionBlock?
14 |
15 | fileprivate let factory: MainFactoryProtocol
16 | fileprivate let router : Routable
17 |
18 | init(with factory: MainFactoryProtocol, router: Routable) {
19 | self.factory = factory
20 | self.router = router
21 | }
22 | }
23 |
24 | // MARK:- Coordinatable
25 | extension MainCoordinator: Coordinatable {
26 | func start() {
27 | performFlow()
28 | }
29 | }
30 |
31 | // MARK:- Private methods
32 | private extension MainCoordinator {
33 | func performFlow() {
34 | let view = factory.makeCharatersView()
35 | router.setRootModule(view, hideBar: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/MainCoordinatorOutput.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainCoordinatorOutput.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol MainCoordinatorOutput: class {
12 | var finishFlow: CompletionBlock? { get set }
13 | }
14 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Main/MainRequestManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainRequestManager.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 11.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class MainRequestManager {
12 |
13 | let mainRequestManager: RequestWrapper
14 |
15 | let configuration = RequestManagerConfiguration(baseURL : Urls.base,
16 | params : ["ts" : Urls.timestamp,
17 | "apikey" : ApiKeys.publicKey,
18 | "hash" : MainRequestManager.hash],
19 | timeout : 20,
20 | logging : true)
21 |
22 | fileprivate static var hash: String! {
23 | return makeHash(Urls.timestamp, publicKey: ApiKeys.publicKey, privateKey: ApiKeys.privateKey)
24 | }
25 |
26 | fileprivate static func makeHash(_ timestamp : NSNumber, publicKey : String, privateKey : String) -> String {
27 | return "\(timestamp)\(privateKey)\(publicKey)".md5()
28 | }
29 |
30 | init() {
31 | mainRequestManager = RequestWrapper(with: configuration)
32 | }
33 |
34 | func getCharacters(offset : Int,
35 | count : Int,
36 | failure : @escaping Failure,
37 | success : @escaping Success<[Character]>) {
38 | mainRequestManager.makeRequest(URL : Urls.Endpoints.characters,
39 | method : .get,
40 | keyPath : "data.results",
41 | failure : failure,
42 | success : success)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Onboarding/Controllers/OnboardingPageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingPageViewController.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 10.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class OnboardingPageViewController: UIPageViewController, OnboardingViewProtocol {
12 |
13 | var onInfo : CompletionBlock?
14 | var onCompletion : CompletionBlock?
15 |
16 | // MARK:- Private variables
17 | fileprivate var numberOfViewControllers: Int {
18 | return images.count
19 | }
20 |
21 | fileprivate let images: [UIImage] = [#imageLiteral(resourceName: "art1"),
22 | #imageLiteral(resourceName: "art2"),
23 | #imageLiteral(resourceName: "art3")]
24 |
25 | // MARK:- UIViewController methods
26 | override func viewDidLoad() {
27 | super.viewDidLoad()
28 | setup()
29 | }
30 | }
31 |
32 | private extension OnboardingPageViewController {
33 | func setup() {
34 | dataSource = self
35 |
36 | if let viewController = showViewController(at: 0) {
37 | set(viewControllers: [viewController])
38 | }
39 | }
40 |
41 | func showViewController(at index: Int) -> OnboardingViewController? {
42 | guard index != NSNotFound, index >= 0, index < numberOfViewControllers else { return nil }
43 | let viewController = OnboardingViewController.controllerFromStoryboard(.onboarding)
44 | viewController.index = index
45 | viewController.image = images[index]
46 | viewController.isLast = index == 2
47 | viewController.onGoMarvel = onCompletion
48 | viewController.onInfo = onInfo
49 |
50 | return viewController
51 | }
52 |
53 | func set(viewControllers: [UIViewController]) {
54 | setViewControllers(viewControllers,
55 | direction : .forward,
56 | animated : true,
57 | completion : nil)
58 | }
59 | }
60 |
61 | // MARK:- UIPageViewControllerDataSource
62 | extension OnboardingPageViewController: UIPageViewControllerDataSource {
63 | func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
64 | var index = (viewController as! OnboardingViewController).index
65 | index -= 1
66 | return showViewController(at: index)
67 | }
68 |
69 | func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
70 | var index = (viewController as! OnboardingViewController).index
71 | index += 1
72 |
73 | return showViewController(at: index)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Onboarding/Controllers/OnboardingViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingViewController.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 06.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class OnboardingViewController: UIViewController {
12 |
13 | // MARK:- Public variables
14 | var index = 0
15 |
16 | var image: UIImage!
17 |
18 | var isLast: Bool = false
19 |
20 | var onGoMarvel : CompletionBlock?
21 | var onInfo : CompletionBlock?
22 |
23 | // MARK:- IBOutlets
24 | @IBOutlet fileprivate weak var imageView: UIImageView!
25 |
26 | @IBOutlet fileprivate weak var pageControl: UIPageControl!
27 |
28 | @IBOutlet fileprivate weak var goMarvelButton: UIButton!
29 |
30 | // MARK:- UIViewController methods
31 | override func viewDidLoad() {
32 | super.viewDidLoad()
33 | setup()
34 | }
35 |
36 | override func viewWillAppear(_ animated: Bool) {
37 | super.viewWillAppear(animated)
38 | setupUI()
39 | }
40 |
41 | @IBAction func goMarvelPressed(_ sender: UIButton) {
42 | onGoMarvel?()
43 | }
44 |
45 | @IBAction func infoPressed(_ sender: UIButton) {
46 | onInfo?()
47 | }
48 | }
49 |
50 | //MARK:- Private methods
51 | extension OnboardingViewController {
52 | func setup() {
53 | setupUI()
54 | }
55 |
56 | func setupUI() {
57 | DispatchQueue.main.async { [unowned self] in
58 | self.imageView.image = self.image
59 | }
60 | pageControl.currentPage = index
61 | goMarvelButton.isHidden = !isLast
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Onboarding/Controllers/OnboardingViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingViewProtocol.swift
3 | // CleanArchitectureWithCoordinatorPatternDemo
4 | //
5 | // Created by Maksim Kazachkov on 06.11.2017.
6 | // Copyright © 2017 Maksim Kazachkov. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol OnboardingViewProtocol: BaseViewProtocol {
12 |
13 | var onCompletion : CompletionBlock? { get set }
14 | var onInfo : CompletionBlock? { get set }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Onboarding/OnboardingCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationCoordinatorOutput.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | class OnboardingCoordinator: BaseCoordinator, OnboardingCoordinatorOutput {
10 |
11 | var finishFlow: CompletionBlock?
12 |
13 | private let factory : OnboardingFactoryProtocol
14 | private let router : Routable
15 |
16 | init(with factory: OnboardingFactoryProtocol, router: Routable) {
17 | self.factory = factory
18 | self.router = router
19 | }
20 | }
21 |
22 | // MARK:- Coordinatable
23 | extension OnboardingCoordinator: Coordinatable {
24 | func start() {
25 | performOnboarding()
26 | }
27 |
28 | func performOnboarding() {
29 | let view = factory.makeOnboardingView()
30 | view.onCompletion = finishFlow
31 | view.onInfo = { [unowned self] in
32 | self.router.toPresent?.showAlert(title : "CREATE AWESOME STUFF WITH THE WORLD'S GREATEST COMIC API!",
33 | message : "The Marvel Comics API allows developers everywhere to access information about Marvel's vast library of comics—from what's coming up, to 70 years ago. ")
34 | }
35 | router.setRootModule(view, hideBar: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CleanArchitectureWithCoordinatorPatternDemo/Source/Modules/Flows/Onboarding/OnboardingCoordinatorOutput.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationCoordinatorOutput.swift
3 | // Worker Dashy
4 | //
5 | // Created by Maksim Kazachkov on 17.08.17.
6 | // Copyright © 2017 Umbrella. All rights reserved.
7 | //
8 |
9 | protocol OnboardingCoordinatorOutput: class {
10 | var finishFlow: CompletionBlock? { get set }
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Kazachkov Maksim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Module VIP.xctemplate/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/Module VIP.xctemplate/.DS_Store
--------------------------------------------------------------------------------
/Module VIP.xctemplate/TemplateIcon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaksimKazachkov/iOS-Clean-Architecture-with-Coordinator-pattern/02c5f4ede8dc901e77dbd27eed0e55c858316047/Module VIP.xctemplate/TemplateIcon.icns
--------------------------------------------------------------------------------
/Module VIP.xctemplate/TemplateInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AllowedTypes
6 |
7 | public.swift-source
8 |
9 | Platforms
10 |
11 | com.apple.platform.iphoneos
12 |
13 | DefaultCompletionName
14 | SwiftVIPModule
15 | Description
16 | Basic Swift clean architecture module template. Creates ViewProtocol, ViewController, PresenterOutput, Presenter, Interactor, Assembly.
17 | Kind
18 | Xcode.IDEKit.TextSubstitutionFileTemplateKind
19 | MainTemplateFile
20 | ___FILEBASENAME___
21 | SortOrder
22 | 1
23 | Options
24 |
25 |
26 | Description
27 | Name of module that you need create
28 | Default
29 |
30 | Identifier
31 | vipModuleName
32 | Name
33 | Module name
34 | Required
35 | YES
36 | Type
37 | text
38 |
39 |
40 | Default
41 | ___VARIABLE_vipModuleName___
42 | Identifier
43 | productName
44 | Type
45 | static
46 |
47 |
48 | Template Author
49 | Kazachkov Maksim
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Module VIP.xctemplate/___FILEBASENAME___Assembly.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ___FILENAME___
3 | // ___PROJECTNAME___
4 | //
5 | // Created ___FULLUSERNAME___ on ___DATE___.
6 | // Copyright © ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ___VARIABLE_productName:identifier___Assemblable: ___VARIABLE_productName:identifier___ViewProtocol, ___VARIABLE_productName:identifier___PresenterOutput {}
12 |
13 | final class ___VARIABLE_productName:identifier___Assembly {
14 | static func assembly(with output: ___VARIABLE_productName:identifier___PresenterOutput) {
15 | let interactor = ___VARIABLE_productName:identifier___Interactor()
16 | let presenter = ___VARIABLE_productName:identifier___Presenter()
17 |
18 | interactor.presenter = presenter
19 | presenter.interactor = interactor
20 | presenter.output = output
21 | output.presenter = presenter
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Module VIP.xctemplate/___FILEBASENAME___Interactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ___FILENAME___
3 | // ___PROJECTNAME___
4 | //
5 | // Created ___FULLUSERNAME___ on ___DATE___.
6 | // Copyright © ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ___VARIABLE_productName:identifier___Interactor {
12 |
13 | weak var presenter: ___VARIABLE_productName:identifier___Presenter?
14 | }
15 |
--------------------------------------------------------------------------------
/Module VIP.xctemplate/___FILEBASENAME___Presenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ___FILENAME___
3 | // ___PROJECTNAME___
4 | //
5 | // Created ___FULLUSERNAME___ on ___DATE___.
6 | // Copyright © ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ___VARIABLE_productName:identifier___PresenterInput: class {
12 |
13 | }
14 |
15 | protocol ___VARIABLE_productName:identifier___PresenterOutput: class {
16 | var presenter: ___VARIABLE_productName:identifier___PresenterInput? { get set }
17 | }
18 |
19 | final class ___VARIABLE_productName:identifier___Presenter {
20 |
21 | weak var output: ___VARIABLE_productName:identifier___PresenterOutput?
22 |
23 | var interactor: ___VARIABLE_productName:identifier___Interactor?
24 | }
25 |
26 | // MARK:- ___VARIABLE_productName:identifier___PresenterInput
27 | extension ___VARIABLE_productName:identifier___Presenter: ___VARIABLE_productName:identifier___PresenterInput {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Module VIP.xctemplate/___FILEBASENAME___ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ___FILENAME___
3 | // ___PROJECTNAME___
4 | //
5 | // Created ___FULLUSERNAME___ on ___DATE___.
6 | // Copyright © ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ___VARIABLE_productName:identifier___ViewController: UIViewController, ___VARIABLE_productName:identifier___Assemblable {
12 |
13 | var presenter: ___VARIABLE_productName:identifier___PresenterInput?
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Module VIP.xctemplate/___FILEBASENAME___ViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ___FILENAME___
3 | // ___PROJECTNAME___
4 | //
5 | // Created ___FULLUSERNAME___ on ___DATE___.
6 | // Copyright © ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ___VARIABLE_productName:identifier___ViewProtocol: BaseViewProtocol {
12 |
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'CleanArchitectureWithCoordinatorPatternDemo' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for CleanArchitectureWithCoordinatorPatternDemo
9 |
10 | pod 'Alamofire'
11 | pod 'AlamofireObjectMapper'
12 | pod 'ObjectMapper'
13 | pod 'Kingfisher'
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (4.5.1)
3 | - AlamofireObjectMapper (5.0.0):
4 | - Alamofire (~> 4.1)
5 | - ObjectMapper (~> 3.0)
6 | - Kingfisher (4.2.0)
7 | - ObjectMapper (3.0.0)
8 |
9 | DEPENDENCIES:
10 | - Alamofire
11 | - AlamofireObjectMapper
12 | - Kingfisher
13 | - ObjectMapper
14 |
15 | SPEC CHECKSUMS:
16 | Alamofire: 2d95912bf4c34f164fdfc335872e8c312acaea4a
17 | AlamofireObjectMapper: 5fafc816351cbbc0d486611aaeba7461c0cbad49
18 | Kingfisher: 9ee7e788d8ba07c3f21ce0d43f33cec310a4f781
19 | ObjectMapper: 92230db59bf8f341a5c3a3cf0b9fbdde3cf0d87f
20 |
21 | PODFILE CHECKSUM: 71da76bb26edc3613e718af2711d9f6b06ba1a28
22 |
23 | COCOAPODS: 1.3.1
24 |
--------------------------------------------------------------------------------
/Pods/Alamofire/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchQueue+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Dispatch
26 | import Foundation
27 |
28 | extension DispatchQueue {
29 | static var userInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) }
30 | static var userInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) }
31 | static var utility: DispatchQueue { return DispatchQueue.global(qos: .utility) }
32 | static var background: DispatchQueue { return DispatchQueue.global(qos: .background) }
33 |
34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) {
35 | asyncAfter(deadline: .now() + delay, execute: closure)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Pods/Alamofire/Source/Notifications.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notifications.swift
3 | //
4 | // Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension Notification.Name {
28 | /// Used as a namespace for all `URLSessionTask` related notifications.
29 | public struct Task {
30 | /// Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`.
31 | public static let DidResume = Notification.Name(rawValue: "org.alamofire.notification.name.task.didResume")
32 |
33 | /// Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`.
34 | public static let DidSuspend = Notification.Name(rawValue: "org.alamofire.notification.name.task.didSuspend")
35 |
36 | /// Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`.
37 | public static let DidCancel = Notification.Name(rawValue: "org.alamofire.notification.name.task.didCancel")
38 |
39 | /// Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`.
40 | public static let DidComplete = Notification.Name(rawValue: "org.alamofire.notification.name.task.didComplete")
41 | }
42 | }
43 |
44 | // MARK: -
45 |
46 | extension Notification {
47 | /// Used as a namespace for all `Notification` user info dictionary keys.
48 | public struct Key {
49 | /// User info dictionary key representing the `URLSessionTask` associated with the notification.
50 | public static let Task = "org.alamofire.notification.key.task"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Pods/AlamofireObjectMapper/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Tristan Himmelman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Wei Wang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Kingfisher
4 | //
5 | // Created by WANG WEI on 2016/09/12.
6 | // Copyright © 2016年 Wei Wang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class Box {
12 | let value: T
13 | init(value: T) {
14 | self.value = value
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/CacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CacheSerializer.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/02.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// An `CacheSerializer` would be used to convert some data to an image object for
30 | /// retrieving from disk cache and vice versa for storing to disk cache.
31 | public protocol CacheSerializer {
32 |
33 | /// Get the serialized data from a provided image
34 | /// and optional original data for caching to disk.
35 | ///
36 | ///
37 | /// - parameter image: The image needed to be serialized.
38 | /// - parameter original: The original data which is just downloaded.
39 | /// If the image is retrieved from cache instead of
40 | /// downloaded, it will be `nil`.
41 | ///
42 | /// - returns: A data which will be stored to cache, or `nil` when no valid
43 | /// data could be serialized.
44 | func data(with image: Image, original: Data?) -> Data?
45 |
46 | /// Get an image deserialized from provided data.
47 | ///
48 | /// - parameter data: The data from which an image should be deserialized.
49 | /// - parameter options: Options for deserialization.
50 | ///
51 | /// - returns: An image deserialized or `nil` when no valid image
52 | /// could be deserialized.
53 | func image(with data: Data, options: KingfisherOptionsInfo?) -> Image?
54 | }
55 |
56 |
57 | /// `DefaultCacheSerializer` is a basic `CacheSerializer` used in default cache of
58 | /// Kingfisher. It could serialize and deserialize PNG, JEPG and GIF images. For
59 | /// image other than these formats, a normalized `pngRepresentation` will be used.
60 | public struct DefaultCacheSerializer: CacheSerializer {
61 |
62 | public static let `default` = DefaultCacheSerializer()
63 | private init() {}
64 |
65 | public func data(with image: Image, original: Data?) -> Data? {
66 | let imageFormat = original?.kf.imageFormat ?? .unknown
67 |
68 | let data: Data?
69 | switch imageFormat {
70 | case .PNG: data = image.kf.pngRepresentation()
71 | case .JPEG: data = image.kf.jpegRepresentation(compressionQuality: 1.0)
72 | case .GIF: data = image.kf.gifRepresentation()
73 | case .unknown: data = original ?? image.kf.normalized.kf.pngRepresentation()
74 | }
75 |
76 | return data
77 | }
78 |
79 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
80 | let options = options ?? KingfisherEmptyOptionsInfo
81 | return Kingfisher.image(
82 | data: data,
83 | scale: options.scaleFactor,
84 | preloadAllAnimationData: options.preloadAllAnimationData,
85 | onlyFirstFrame: options.onlyLoadFirstFrame)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/FormatIndicatedCacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Junyu Kuang on 5/28/17.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// `FormatIndicatedCacheSerializer` let you indicate an image format for serialized caches.
30 | ///
31 | /// It could serialize and deserialize PNG, JEPG and GIF images. For
32 | /// image other than these formats, a normalized `pngRepresentation` will be used.
33 | ///
34 | /// Example:
35 | /// ````
36 | /// private let profileImageSize = CGSize(width: 44, height: 44)
37 | ///
38 | /// private let imageProcessor = RoundCornerImageProcessor(
39 | /// cornerRadius: profileImageSize.width / 2, targetSize: profileImageSize)
40 | ///
41 | /// private let optionsInfo: KingfisherOptionsInfo = [
42 | /// .cacheSerializer(FormatIndicatedCacheSerializer.png),
43 | /// .backgroundDecode, .processor(imageProcessor), .scaleFactor(UIScreen.main.scale)]
44 | ///
45 | /// extension UIImageView {
46 | /// func setProfileImage(with url: URL) {
47 | /// // Image will always cached as PNG format to preserve alpha channel for round rect.
48 | /// _ = kf.setImage(with: url, options: optionsInfo)
49 | /// }
50 | ///}
51 | /// ````
52 | public struct FormatIndicatedCacheSerializer: CacheSerializer {
53 |
54 | public static let png = FormatIndicatedCacheSerializer(imageFormat: .PNG)
55 | public static let jpeg = FormatIndicatedCacheSerializer(imageFormat: .JPEG)
56 | public static let gif = FormatIndicatedCacheSerializer(imageFormat: .GIF)
57 |
58 | /// The indicated image format.
59 | private let imageFormat: ImageFormat
60 |
61 | public func data(with image: Image, original: Data?) -> Data? {
62 |
63 | func imageData(withFormat imageFormat: ImageFormat) -> Data? {
64 | switch imageFormat {
65 | case .PNG: return image.kf.pngRepresentation()
66 | case .JPEG: return image.kf.jpegRepresentation(compressionQuality: 1.0)
67 | case .GIF: return image.kf.gifRepresentation()
68 | case .unknown: return nil
69 | }
70 | }
71 |
72 | // generate data with indicated image format
73 | if let data = imageData(withFormat: imageFormat) {
74 | return data
75 | }
76 |
77 | let originalFormat = original?.kf.imageFormat ?? .unknown
78 |
79 | // generate data with original image's format
80 | if originalFormat != imageFormat, let data = imageData(withFormat: originalFormat) {
81 | return data
82 | }
83 |
84 | return original ?? image.kf.normalized.kf.pngRepresentation()
85 | }
86 |
87 | /// Same implementation as `DefaultCacheSerializer`.
88 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
89 | let options = options ?? KingfisherEmptyOptionsInfo
90 | return Kingfisher.image(
91 | data: data,
92 | scale: options.scaleFactor,
93 | preloadAllAnimationData: options.preloadAllAnimationData,
94 | onlyFirstFrame: options.onlyLoadFirstFrame)
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/ImageTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransition.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/9/18.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | // Not implemented for macOS and watchOS yet.
29 |
30 | import AppKit
31 |
32 | /// Image transition is not supported on macOS.
33 | public enum ImageTransition {
34 | case none
35 | var duration: TimeInterval {
36 | return 0
37 | }
38 | }
39 |
40 | #elseif os(watchOS)
41 | import UIKit
42 | /// Image transition is not supported on watchOS.
43 | public enum ImageTransition {
44 | case none
45 | var duration: TimeInterval {
46 | return 0
47 | }
48 | }
49 | #else
50 | import UIKit
51 |
52 | /**
53 | Transition effect which will be used when an image downloaded and set by `UIImageView` extension API in Kingfisher.
54 | You can assign an enum value with transition duration as an item in `KingfisherOptionsInfo`
55 | to enable the animation transition.
56 |
57 | Apple's UIViewAnimationOptions is used under the hood.
58 | For custom transition, you should specified your own transition options, animations and
59 | comletion handler as well.
60 | */
61 | public enum ImageTransition {
62 | /// No animation transistion.
63 | case none
64 |
65 | /// Fade in the loaded image.
66 | case fade(TimeInterval)
67 |
68 | /// Flip from left transition.
69 | case flipFromLeft(TimeInterval)
70 |
71 | /// Flip from right transition.
72 | case flipFromRight(TimeInterval)
73 |
74 | /// Flip from top transition.
75 | case flipFromTop(TimeInterval)
76 |
77 | /// Flip from bottom transition.
78 | case flipFromBottom(TimeInterval)
79 |
80 | /// Custom transition.
81 | case custom(duration: TimeInterval,
82 | options: UIViewAnimationOptions,
83 | animations: ((UIImageView, UIImage) -> Void)?,
84 | completion: ((Bool) -> Void)?)
85 |
86 | var duration: TimeInterval {
87 | switch self {
88 | case .none: return 0
89 | case .fade(let duration): return duration
90 |
91 | case .flipFromLeft(let duration): return duration
92 | case .flipFromRight(let duration): return duration
93 | case .flipFromTop(let duration): return duration
94 | case .flipFromBottom(let duration): return duration
95 |
96 | case .custom(let duration, _, _, _): return duration
97 | }
98 | }
99 |
100 | var animationOptions: UIViewAnimationOptions {
101 | switch self {
102 | case .none: return []
103 | case .fade(_): return .transitionCrossDissolve
104 |
105 | case .flipFromLeft(_): return .transitionFlipFromLeft
106 | case .flipFromRight(_): return .transitionFlipFromRight
107 | case .flipFromTop(_): return .transitionFlipFromTop
108 | case .flipFromBottom(_): return .transitionFlipFromBottom
109 |
110 | case .custom(_, let options, _, _): return options
111 | }
112 | }
113 |
114 | var animations: ((UIImageView, UIImage) -> Void)? {
115 | switch self {
116 | case .custom(_, _, let animations, _): return animations
117 | default: return { $0.image = $1 }
118 | }
119 | }
120 |
121 | var completion: ((Bool) -> Void)? {
122 | switch self {
123 | case .custom(_, _, _, let completion): return completion
124 | default: return nil
125 | }
126 | }
127 | }
128 | #endif
129 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/Kingfisher.h:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.h
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #import
28 |
29 | //! Project version number for Kingfisher.
30 | FOUNDATION_EXPORT double KingfisherVersionNumber;
31 |
32 | //! Project version string for Kingfisher.
33 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
34 |
35 | // In this header, you should import all the public headers of your framework using statements like #import
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 16/9/14.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 | import ImageIO
29 |
30 | #if os(macOS)
31 | import AppKit
32 | public typealias Image = NSImage
33 | public typealias View = NSView
34 | public typealias Color = NSColor
35 | public typealias ImageView = NSImageView
36 | public typealias Button = NSButton
37 | #else
38 | import UIKit
39 | public typealias Image = UIImage
40 | public typealias Color = UIColor
41 | #if !os(watchOS)
42 | public typealias ImageView = UIImageView
43 | public typealias View = UIView
44 | public typealias Button = UIButton
45 | #endif
46 | #endif
47 |
48 | public final class Kingfisher {
49 | public let base: Base
50 | public init(_ base: Base) {
51 | self.base = base
52 | }
53 | }
54 |
55 | /**
56 | A type that has Kingfisher extensions.
57 | */
58 | public protocol KingfisherCompatible {
59 | associatedtype CompatibleType
60 | var kf: CompatibleType { get }
61 | }
62 |
63 | public extension KingfisherCompatible {
64 | public var kf: Kingfisher {
65 | get { return Kingfisher(self) }
66 | }
67 | }
68 |
69 | extension Image: KingfisherCompatible { }
70 | #if !os(watchOS)
71 | extension ImageView: KingfisherCompatible { }
72 | extension Button: KingfisherCompatible { }
73 | #endif
74 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/Placeholder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Placeholder.swift
3 | // Kingfisher
4 | //
5 | // Created by Tieme van Veen on 28/08/2017.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | import AppKit
29 | #else
30 | import UIKit
31 | #endif
32 |
33 |
34 | /// Represent a placeholder type which could be set while loading as well as
35 | /// loading finished without getting an image.
36 | public protocol Placeholder {
37 |
38 | /// How the placeholder should be added to a given image view.
39 | func add(to imageView: ImageView)
40 |
41 | /// How the placeholder should be removed from a given image view.
42 | func remove(from imageView: ImageView)
43 | }
44 |
45 | /// Default implementation of an image placeholder. The image will be set or
46 | /// reset directly for `image` property of the image view.
47 | extension Placeholder where Self: Image {
48 |
49 | /// How the placeholder should be added to a given image view.
50 | public func add(to imageView: ImageView) { imageView.image = self }
51 |
52 | /// How the placeholder should be removed from a given image view.
53 | public func remove(from imageView: ImageView) { imageView.image = nil }
54 | }
55 |
56 | extension Image: Placeholder {}
57 |
58 | /// Default implementation of an arbitrary view as placeholder. The view will be
59 | /// added as a subview when adding and be removed from its super view when removing.
60 | ///
61 | /// To use your customize View type as placeholder, simply let it conforming to
62 | /// `Placeholder` by `extension MyView: Placeholder {}`.
63 | extension Placeholder where Self: View {
64 |
65 | /// How the placeholder should be added to a given image view.
66 | public func add(to imageView: ImageView) {
67 | imageView.addSubview(self)
68 |
69 | self.translatesAutoresizingMaskIntoConstraints = false
70 | NSLayoutConstraint.activate([
71 | NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: imageView, attribute: .centerX, multiplier: 1, constant: 0),
72 | NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: imageView, attribute: .centerY, multiplier: 1, constant: 0),
73 | NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: imageView, attribute: .height, multiplier: 1, constant: 0),
74 | NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: imageView, attribute: .width, multiplier: 1, constant: 0)
75 | ])
76 | }
77 |
78 | /// How the placeholder should be removed from a given image view.
79 | public func remove(from imageView: ImageView) {
80 | self.removeFromSuperview()
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/RequestModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/05.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// Request modifier of image downloader.
30 | public protocol ImageDownloadRequestModifier {
31 | func modified(for request: URLRequest) -> URLRequest?
32 | }
33 |
34 | struct NoModifier: ImageDownloadRequestModifier {
35 | static let `default` = NoModifier()
36 | private init() {}
37 | func modified(for request: URLRequest) -> URLRequest? {
38 | return request
39 | }
40 | }
41 |
42 | public struct AnyModifier: ImageDownloadRequestModifier {
43 |
44 | let block: (URLRequest) -> URLRequest?
45 |
46 | public func modified(for request: URLRequest) -> URLRequest? {
47 | return block(request)
48 | }
49 |
50 | public init(modify: @escaping (URLRequest) -> URLRequest? ) {
51 | block = modify
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/Resource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Resource.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | /// `Resource` protocol defines how to download and cache a resource from network.
31 | public protocol Resource {
32 | /// The key used in cache.
33 | var cacheKey: String { get }
34 |
35 | /// The target image URL.
36 | var downloadURL: URL { get }
37 | }
38 |
39 | /**
40 | ImageResource is a simple combination of `downloadURL` and `cacheKey`.
41 |
42 | When passed to image view set methods, Kingfisher will try to download the target
43 | image from the `downloadURL`, and then store it with the `cacheKey` as the key in cache.
44 | */
45 | public struct ImageResource: Resource {
46 | /// The key used in cache.
47 | public let cacheKey: String
48 |
49 | /// The target image URL.
50 | public let downloadURL: URL
51 |
52 | /**
53 | Create a resource.
54 |
55 | - parameter downloadURL: The target image URL.
56 | - parameter cacheKey: The cache key. If `nil`, Kingfisher will use the `absoluteString` of `downloadURL` as the key.
57 |
58 | - returns: A resource.
59 | */
60 | public init(downloadURL: URL, cacheKey: String? = nil) {
61 | self.downloadURL = downloadURL
62 | self.cacheKey = cacheKey ?? downloadURL.absoluteString
63 | }
64 | }
65 |
66 | /**
67 | URL conforms to `Resource` in Kingfisher.
68 | The `absoluteString` of this URL is used as `cacheKey`. And the URL itself will be used as `downloadURL`.
69 | If you need customize the url and/or cache key, use `ImageResource` instead.
70 | */
71 | extension URL: Resource {
72 | public var cacheKey: String { return absoluteString }
73 | public var downloadURL: URL { return self }
74 | }
75 |
--------------------------------------------------------------------------------
/Pods/Kingfisher/Sources/ThreadHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreadHelper.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/10/9.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | extension DispatchQueue {
30 | // This method will dispatch the `block` to self.
31 | // If `self` is the main queue, and current thread is main thread, the block
32 | // will be invoked immediately instead of being dispatched.
33 | func safeAsync(_ block: @escaping ()->()) {
34 | if self === DispatchQueue.main && Thread.isMainThread {
35 | block()
36 | } else {
37 | async { block() }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (4.5.1)
3 | - AlamofireObjectMapper (5.0.0):
4 | - Alamofire (~> 4.1)
5 | - ObjectMapper (~> 3.0)
6 | - Kingfisher (4.2.0)
7 | - ObjectMapper (3.0.0)
8 |
9 | DEPENDENCIES:
10 | - Alamofire
11 | - AlamofireObjectMapper
12 | - Kingfisher
13 | - ObjectMapper
14 |
15 | SPEC CHECKSUMS:
16 | Alamofire: 2d95912bf4c34f164fdfc335872e8c312acaea4a
17 | AlamofireObjectMapper: 5fafc816351cbbc0d486611aaeba7461c0cbad49
18 | Kingfisher: 9ee7e788d8ba07c3f21ce0d43f33cec310a4f781
19 | ObjectMapper: 92230db59bf8f341a5c3a3cf0b9fbdde3cf0d87f
20 |
21 | PODFILE CHECKSUM: 71da76bb26edc3613e718af2711d9f6b06ba1a28
22 |
23 | COCOAPODS: 1.3.1
24 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2014 Hearst
3 |
4 | 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:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | 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.
9 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomDateFormatTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Dan McCracken on 3/8/15.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class CustomDateFormatTransform: DateFormatterTransform {
32 |
33 | public init(formatString: String) {
34 | let formatter = DateFormatter()
35 | formatter.locale = Locale(identifier: "en_US_POSIX")
36 | formatter.dateFormat = formatString
37 |
38 | super.init(dateFormatter: formatter)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/DataTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Yagrushkin, Evgeny on 8/30/16.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class DataTransform: TransformType {
32 | public typealias Object = Data
33 | public typealias JSON = String
34 |
35 | public init() {}
36 |
37 | open func transformFromJSON(_ value: Any?) -> Data? {
38 | guard let string = value as? String else{
39 | return nil
40 | }
41 | return Data(base64Encoded: string)
42 | }
43 |
44 | open func transformToJSON(_ value: Data?) -> String? {
45 | guard let data = value else{
46 | return nil
47 | }
48 | return data.base64EncodedString()
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/DateFormatterTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateFormatterTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 2015-03-09.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class DateFormatterTransform: TransformType {
32 | public typealias Object = Date
33 | public typealias JSON = String
34 |
35 | public let dateFormatter: DateFormatter
36 |
37 | public init(dateFormatter: DateFormatter) {
38 | self.dateFormatter = dateFormatter
39 | }
40 |
41 | open func transformFromJSON(_ value: Any?) -> Date? {
42 | if let dateString = value as? String {
43 | return dateFormatter.date(from: dateString)
44 | }
45 | return nil
46 | }
47 |
48 | open func transformToJSON(_ value: Date?) -> String? {
49 | if let date = value {
50 | return dateFormatter.string(from: date)
51 | }
52 | return nil
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/DateTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 2014-10-13.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class DateTransform: TransformType {
32 | public typealias Object = Date
33 | public typealias JSON = Double
34 |
35 | public init() {}
36 |
37 | open func transformFromJSON(_ value: Any?) -> Date? {
38 | if let timeInt = value as? Double {
39 | return Date(timeIntervalSince1970: TimeInterval(timeInt))
40 | }
41 |
42 | if let timeStr = value as? String {
43 | return Date(timeIntervalSince1970: TimeInterval(atof(timeStr)))
44 | }
45 |
46 | return nil
47 | }
48 |
49 | open func transformToJSON(_ value: Date?) -> Double? {
50 | if let date = value {
51 | return Double(date.timeIntervalSince1970)
52 | }
53 | return nil
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/DictionaryTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DictionaryTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Milen Halachev on 7/20/16.
6 | // Copyright © 2016 hearst. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | ///Transforms [String: AnyObject] <-> [Key: Value] where Key is RawRepresentable as String, Value is Mappable
12 | public struct DictionaryTransform: TransformType where Key: Hashable, Key: RawRepresentable, Key.RawValue == String, Value: Mappable {
13 |
14 | public init() {
15 |
16 | }
17 |
18 | public func transformFromJSON(_ value: Any?) -> [Key: Value]? {
19 |
20 | guard let json = value as? [String: Any] else {
21 |
22 | return nil
23 | }
24 |
25 | let result = json.reduce([:]) { (result, element) -> [Key: Value] in
26 |
27 | guard
28 | let key = Key(rawValue: element.0),
29 | let valueJSON = element.1 as? [String: Any],
30 | let value = Value(JSON: valueJSON)
31 | else {
32 |
33 | return result
34 | }
35 |
36 | var result = result
37 | result[key] = value
38 | return result
39 | }
40 |
41 | return result
42 | }
43 |
44 | public func transformToJSON(_ value: [Key: Value]?) -> Any? {
45 |
46 | let result = value?.reduce([:]) { (result, element) -> [String: Any] in
47 |
48 | let key = element.0.rawValue
49 | let value = element.1.toJSON()
50 |
51 | var result = result
52 | result[key] = value
53 | return result
54 | }
55 |
56 | return result
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/EnumOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnumOperators.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 2016-09-26.
6 | // Copyright © 2016 hearst. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 | // MARK:- Raw Representable types
13 |
14 | /// Object of Raw Representable type
15 | public func <- (left: inout T, right: Map) {
16 | left <- (right, EnumTransform())
17 | }
18 |
19 | public func >>> (left: T, right: Map) {
20 | left >>> (right, EnumTransform())
21 | }
22 |
23 |
24 | /// Optional Object of Raw Representable type
25 | public func <- (left: inout T?, right: Map) {
26 | left <- (right, EnumTransform())
27 | }
28 |
29 | public func >>> (left: T?, right: Map) {
30 | left >>> (right, EnumTransform())
31 | }
32 |
33 |
34 | /// Implicitly Unwrapped Optional Object of Raw Representable type
35 | public func <- (left: inout T!, right: Map) {
36 | left <- (right, EnumTransform())
37 | }
38 |
39 | // MARK:- Arrays of Raw Representable type
40 |
41 | /// Array of Raw Representable object
42 | public func <- (left: inout [T], right: Map) {
43 | left <- (right, EnumTransform())
44 | }
45 |
46 | public func >>> (left: [T], right: Map) {
47 | left >>> (right, EnumTransform())
48 | }
49 |
50 |
51 | /// Array of Raw Representable object
52 | public func <- (left: inout [T]?, right: Map) {
53 | left <- (right, EnumTransform())
54 | }
55 |
56 | public func >>> (left: [T]?, right: Map) {
57 | left >>> (right, EnumTransform())
58 | }
59 |
60 |
61 | /// Array of Raw Representable object
62 | public func <- (left: inout [T]!, right: Map) {
63 | left <- (right, EnumTransform())
64 | }
65 |
66 | // MARK:- Dictionaries of Raw Representable type
67 |
68 | /// Dictionary of Raw Representable object
69 | public func <- (left: inout [String: T], right: Map) {
70 | left <- (right, EnumTransform())
71 | }
72 |
73 | public func >>> (left: [String: T], right: Map) {
74 | left >>> (right, EnumTransform())
75 | }
76 |
77 |
78 | /// Dictionary of Raw Representable object
79 | public func <- (left: inout [String: T]?, right: Map) {
80 | left <- (right, EnumTransform())
81 | }
82 |
83 | public func >>> (left: [String: T]?, right: Map) {
84 | left >>> (right, EnumTransform())
85 | }
86 |
87 |
88 | /// Dictionary of Raw Representable object
89 | public func <- (left: inout [String: T]!, right: Map) {
90 | left <- (right, EnumTransform())
91 | }
92 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/EnumTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnumTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Kaan Dedeoglu on 3/20/15.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class EnumTransform: TransformType {
32 | public typealias Object = T
33 | public typealias JSON = T.RawValue
34 |
35 | public init() {}
36 |
37 | open func transformFromJSON(_ value: Any?) -> T? {
38 | if let raw = value as? T.RawValue {
39 | return T(rawValue: raw)
40 | }
41 | return nil
42 | }
43 |
44 | open func transformToJSON(_ value: T?) -> T.RawValue? {
45 | if let obj = value {
46 | return obj.rawValue
47 | }
48 | return nil
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/HexColorTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HexColorTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Vitaliy Kuzmenko on 10/10/16.
6 | // Copyright © 2016 hearst. All rights reserved.
7 | //
8 |
9 | #if os(iOS) || os(tvOS) || os(watchOS)
10 | import UIKit
11 | #elseif os(macOS)
12 | import Cocoa
13 | #endif
14 |
15 | #if os(iOS) || os(tvOS) || os(watchOS) || os(macOS)
16 | open class HexColorTransform: TransformType {
17 |
18 | #if os(iOS) || os(tvOS) || os(watchOS)
19 | public typealias Object = UIColor
20 | #else
21 | public typealias Object = NSColor
22 | #endif
23 |
24 | public typealias JSON = String
25 |
26 | var prefix: Bool = false
27 |
28 | var alpha: Bool = false
29 |
30 | public init(prefixToJSON: Bool = false, alphaToJSON: Bool = false) {
31 | alpha = alphaToJSON
32 | prefix = prefixToJSON
33 | }
34 |
35 | open func transformFromJSON(_ value: Any?) -> Object? {
36 | if let rgba = value as? String {
37 | if rgba.hasPrefix("#") {
38 | let index = rgba.characters.index(rgba.startIndex, offsetBy: 1)
39 | let hex = String(rgba[index...])
40 | return getColor(hex: hex)
41 | } else {
42 | return getColor(hex: rgba)
43 | }
44 | }
45 | return nil
46 | }
47 |
48 | open func transformToJSON(_ value: Object?) -> JSON? {
49 | if let value = value {
50 | return hexString(color: value)
51 | }
52 | return nil
53 | }
54 |
55 | fileprivate func hexString(color: Object) -> String {
56 | let comps = color.cgColor.components!
57 | let compsCount = color.cgColor.numberOfComponents
58 | let r: Int
59 | let g: Int
60 | var b: Int
61 | let a = Int(comps[compsCount - 1] * 255)
62 | if compsCount == 4 { // RGBA
63 | r = Int(comps[0] * 255)
64 | g = Int(comps[1] * 255)
65 | b = Int(comps[2] * 255)
66 | } else { // Grayscale
67 | r = Int(comps[0] * 255)
68 | g = Int(comps[0] * 255)
69 | b = Int(comps[0] * 255)
70 | }
71 | var hexString: String = ""
72 | if prefix {
73 | hexString = "#"
74 | }
75 | hexString += String(format: "%02X%02X%02X", r, g, b)
76 |
77 | if alpha {
78 | hexString += String(format: "%02X", a)
79 | }
80 | return hexString
81 | }
82 |
83 | fileprivate func getColor(hex: String) -> Object? {
84 | var red: CGFloat = 0.0
85 | var green: CGFloat = 0.0
86 | var blue: CGFloat = 0.0
87 | var alpha: CGFloat = 1.0
88 |
89 | let scanner = Scanner(string: hex)
90 | var hexValue: CUnsignedLongLong = 0
91 | if scanner.scanHexInt64(&hexValue) {
92 | switch (hex.characters.count) {
93 | case 3:
94 | red = CGFloat((hexValue & 0xF00) >> 8) / 15.0
95 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0
96 | blue = CGFloat(hexValue & 0x00F) / 15.0
97 | case 4:
98 | red = CGFloat((hexValue & 0xF000) >> 12) / 15.0
99 | green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0
100 | blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0
101 | alpha = CGFloat(hexValue & 0x000F) / 15.0
102 | case 6:
103 | red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0
104 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0
105 | blue = CGFloat(hexValue & 0x0000FF) / 255.0
106 | case 8:
107 | red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0
108 | green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0
109 | blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0
110 | alpha = CGFloat(hexValue & 0x000000FF) / 255.0
111 | default:
112 | // Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8
113 | return nil
114 | }
115 | } else {
116 | // "Scan hex error
117 | return nil
118 | }
119 | #if os(iOS) || os(tvOS) || os(watchOS)
120 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
121 | #else
122 | return NSColor(calibratedRed: red, green: green, blue: blue, alpha: alpha)
123 | #endif
124 | }
125 | }
126 | #endif
127 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ISO8601DateTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Jean-Pierre Mouilleseaux on 21 Nov 2014.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | public extension DateFormatter {
32 | public convenience init(withFormat format : String, locale : String) {
33 | self.init()
34 | self.locale = Locale(identifier: locale)
35 | dateFormat = format
36 | }
37 | }
38 |
39 | open class ISO8601DateTransform: DateFormatterTransform {
40 |
41 | static let reusableISODateFormatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ssZZZZZ", locale: "en_US_POSIX")
42 |
43 | public init() {
44 | super.init(dateFormatter: ISO8601DateTransform.reusableISODateFormatter)
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/IntegerOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntegerOperators.swift
3 | // ObjectMapper
4 | //
5 | // Created by Suyeol Jeon on 17/02/2017.
6 | // Copyright © 2017 hearst. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Signed Integer
12 |
13 | /// SignedInteger mapping
14 | public func <- (left: inout T, right: Map) {
15 | switch right.mappingType {
16 | case .fromJSON where right.isKeyPresent:
17 | let value: T = toSignedInteger(right.currentValue) ?? 0
18 | FromJSON.basicType(&left, object: value)
19 | case .toJSON:
20 | left >>> right
21 | default: ()
22 | }
23 | }
24 |
25 | /// Optional SignedInteger mapping
26 | public func <- (left: inout T?, right: Map) {
27 | switch right.mappingType {
28 | case .fromJSON where right.isKeyPresent:
29 | let value: T? = toSignedInteger(right.currentValue)
30 | FromJSON.basicType(&left, object: value)
31 | case .toJSON:
32 | left >>> right
33 | default: ()
34 | }
35 | }
36 |
37 | /// ImplicitlyUnwrappedOptional SignedInteger mapping
38 | public func <- (left: inout T!, right: Map) {
39 | switch right.mappingType {
40 | case .fromJSON where right.isKeyPresent:
41 | let value: T! = toSignedInteger(right.currentValue)
42 | FromJSON.basicType(&left, object: value)
43 | case .toJSON:
44 | left >>> right
45 | default: ()
46 | }
47 | }
48 |
49 |
50 | // MARK: - Unsigned Integer
51 |
52 | /// UnsignedInteger mapping
53 | public func <- (left: inout T, right: Map) {
54 | switch right.mappingType {
55 | case .fromJSON where right.isKeyPresent:
56 | let value: T = toUnsignedInteger(right.currentValue) ?? 0
57 | FromJSON.basicType(&left, object: value)
58 | case .toJSON:
59 | left >>> right
60 | default: ()
61 | }
62 | }
63 |
64 |
65 | /// Optional UnsignedInteger mapping
66 | public func <- (left: inout T?, right: Map) {
67 | switch right.mappingType {
68 | case .fromJSON where right.isKeyPresent:
69 | let value: T? = toUnsignedInteger(right.currentValue)
70 | FromJSON.basicType(&left, object: value)
71 | case .toJSON:
72 | left >>> right
73 | default: ()
74 | }
75 | }
76 |
77 | /// ImplicitlyUnwrappedOptional UnsignedInteger mapping
78 | public func <- (left: inout T!, right: Map) {
79 | switch right.mappingType {
80 | case .fromJSON where right.isKeyPresent:
81 | let value: T! = toUnsignedInteger(right.currentValue)
82 | FromJSON.basicType(&left, object: value)
83 | case .toJSON:
84 | left >>> right
85 | default: ()
86 | }
87 | }
88 |
89 | // MARK: - Casting Utils
90 |
91 | /// Convert any value to `SignedInteger`.
92 | private func toSignedInteger(_ value: Any?) -> T? {
93 | guard
94 | let value = value,
95 | case let number as NSNumber = value
96 | else {
97 | return nil
98 | }
99 |
100 | if T.self == Int.self, let x = Int(exactly: number.int64Value) {
101 | return T.init(x)
102 | }
103 | if T.self == Int8.self, let x = Int8(exactly: number.int64Value) {
104 | return T.init(x)
105 | }
106 | if T.self == Int16.self, let x = Int16(exactly: number.int64Value) {
107 | return T.init(x)
108 | }
109 | if T.self == Int32.self, let x = Int32(exactly: number.int64Value) {
110 | return T.init(x)
111 | }
112 | if T.self == Int64.self, let x = Int64(exactly: number.int64Value) {
113 | return T.init(x)
114 | }
115 |
116 | return nil
117 | }
118 |
119 | /// Convert any value to `UnsignedInteger`.
120 | private func toUnsignedInteger(_ value: Any?) -> T? {
121 | guard
122 | let value = value,
123 | case let number as NSNumber = value
124 | else {
125 | return nil
126 | }
127 |
128 | if T.self == UInt.self, let x = UInt(exactly: number.uint64Value) {
129 | return T.init(x)
130 | }
131 | if T.self == UInt8.self, let x = UInt8(exactly: number.uint64Value) {
132 | return T.init(x)
133 | }
134 | if T.self == UInt16.self, let x = UInt16(exactly: number.uint64Value) {
135 | return T.init(x)
136 | }
137 | if T.self == UInt32.self, let x = UInt32(exactly: number.uint64Value) {
138 | return T.init(x)
139 | }
140 | if T.self == UInt64.self, let x = UInt64(exactly: number.uint64Value) {
141 | return T.init(x)
142 | }
143 |
144 | return nil
145 | }
146 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/MapError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapError.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 2016-09-26.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | public struct MapError: Error {
32 | public var key: String?
33 | public var currentValue: Any?
34 | public var reason: String?
35 | public var file: StaticString?
36 | public var function: StaticString?
37 | public var line: UInt?
38 |
39 | public init(key: String?, currentValue: Any?, reason: String?, file: StaticString? = nil, function: StaticString? = nil, line: UInt? = nil) {
40 | self.key = key
41 | self.currentValue = currentValue
42 | self.reason = reason
43 | self.file = file
44 | self.function = function
45 | self.line = line
46 | }
47 | }
48 |
49 | extension MapError: CustomStringConvertible {
50 |
51 | private var location: String? {
52 | guard let file = file, let function = function, let line = line else { return nil }
53 | let fileName = ((String(describing: file).components(separatedBy: "/").last ?? "").components(separatedBy: ".").first ?? "")
54 | return "\(fileName).\(function):\(line)"
55 | }
56 |
57 | public var description: String {
58 | let info: [(String, Any?)] = [
59 | ("- reason", reason),
60 | ("- location", location),
61 | ("- key", key),
62 | ("- currentValue", currentValue),
63 | ]
64 | let infoString = info.map { "\($0.0): \($0.1 ?? "nil")" }.joined(separator: "\n")
65 | return "Got an error while mapping.\n\(infoString)"
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/Mappable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Mappable.swift
3 | // ObjectMapper
4 | //
5 | // Created by Scott Hoyt on 10/25/15.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | /// BaseMappable should not be implemented directly. Mappable or StaticMappable should be used instead
32 | public protocol BaseMappable {
33 | /// This function is where all variable mappings should occur. It is executed by Mapper during the mapping (serialization and deserialization) process.
34 | mutating func mapping(map: Map)
35 | }
36 |
37 | public protocol Mappable: BaseMappable {
38 | /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point
39 | init?(map: Map)
40 | }
41 |
42 | public protocol StaticMappable: BaseMappable {
43 | /// This is function that can be used to:
44 | /// 1) provide an existing cached object to be used for mapping
45 | /// 2) return an object of another class (which conforms to BaseMappable) to be used for mapping. For instance, you may inspect the JSON to infer the type of object that should be used for any given mapping
46 | static func objectForMapping(map: Map) -> BaseMappable?
47 | }
48 |
49 | public extension BaseMappable {
50 |
51 | /// Initializes object from a JSON String
52 | public init?(JSONString: String, context: MapContext? = nil) {
53 | if let obj: Self = Mapper(context: context).map(JSONString: JSONString) {
54 | self = obj
55 | } else {
56 | return nil
57 | }
58 | }
59 |
60 | /// Initializes object from a JSON Dictionary
61 | public init?(JSON: [String: Any], context: MapContext? = nil) {
62 | if let obj: Self = Mapper(context: context).map(JSON: JSON) {
63 | self = obj
64 | } else {
65 | return nil
66 | }
67 | }
68 |
69 | /// Returns the JSON Dictionary for the object
70 | public func toJSON() -> [String: Any] {
71 | return Mapper().toJSON(self)
72 | }
73 |
74 | /// Returns the JSON String for the object
75 | public func toJSONString(prettyPrint: Bool = false) -> String? {
76 | return Mapper().toJSONString(self, prettyPrint: prettyPrint)
77 | }
78 | }
79 |
80 | public extension Array where Element: BaseMappable {
81 |
82 | /// Initialize Array from a JSON String
83 | public init?(JSONString: String, context: MapContext? = nil) {
84 | if let obj: [Element] = Mapper(context: context).mapArray(JSONString: JSONString) {
85 | self = obj
86 | } else {
87 | return nil
88 | }
89 | }
90 |
91 | /// Initialize Array from a JSON Array
92 | public init(JSONArray: [[String: Any]], context: MapContext? = nil) {
93 | let obj: [Element] = Mapper(context: context).mapArray(JSONArray: JSONArray)
94 | self = obj
95 | }
96 |
97 | /// Returns the JSON Array
98 | public func toJSON() -> [[String: Any]] {
99 | return Mapper().toJSONArray(self)
100 | }
101 |
102 | /// Returns the JSON String for the object
103 | public func toJSONString(prettyPrint: Bool = false) -> String? {
104 | return Mapper().toJSONString(self, prettyPrint: prettyPrint)
105 | }
106 | }
107 |
108 | public extension Set where Element: BaseMappable {
109 |
110 | /// Initializes a set from a JSON String
111 | public init?(JSONString: String, context: MapContext? = nil) {
112 | if let obj: Set = Mapper(context: context).mapSet(JSONString: JSONString) {
113 | self = obj
114 | } else {
115 | return nil
116 | }
117 | }
118 |
119 | /// Initializes a set from JSON
120 | public init?(JSONArray: [[String: Any]], context: MapContext? = nil) {
121 | guard let obj = Mapper(context: context).mapSet(JSONArray: JSONArray) as Set? else {
122 | return nil
123 | }
124 | self = obj
125 | }
126 |
127 | /// Returns the JSON Set
128 | public func toJSON() -> [[String: Any]] {
129 | return Mapper().toJSONSet(self)
130 | }
131 |
132 | /// Returns the JSON String for the object
133 | public func toJSONString(prettyPrint: Bool = false) -> String? {
134 | return Mapper().toJSONString(self, prettyPrint: prettyPrint)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransformOf.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 8/22/16.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class NSDecimalNumberTransform: TransformType {
32 | public typealias Object = NSDecimalNumber
33 | public typealias JSON = String
34 |
35 | public init() {}
36 |
37 | open func transformFromJSON(_ value: Any?) -> NSDecimalNumber? {
38 | if let string = value as? String {
39 | return NSDecimalNumber(string: string)
40 | } else if let number = value as? NSNumber {
41 | return NSDecimalNumber(decimal: number.decimalValue)
42 | } else if let double = value as? Double {
43 | return NSDecimalNumber(floatLiteral: double)
44 | }
45 | return nil
46 | }
47 |
48 | open func transformToJSON(_ value: NSDecimalNumber?) -> String? {
49 | guard let value = value else { return nil }
50 | return value.description
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/TransformOf.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransformOf.swift
3 | // ObjectMapper
4 | //
5 | // Created by Syo Ikeda on 1/23/15.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | open class TransformOf: TransformType {
30 | public typealias Object = ObjectType
31 | public typealias JSON = JSONType
32 |
33 | private let fromJSON: (JSONType?) -> ObjectType?
34 | private let toJSON: (ObjectType?) -> JSONType?
35 |
36 | public init(fromJSON: @escaping(JSONType?) -> ObjectType?, toJSON: @escaping(ObjectType?) -> JSONType?) {
37 | self.fromJSON = fromJSON
38 | self.toJSON = toJSON
39 | }
40 |
41 | open func transformFromJSON(_ value: Any?) -> ObjectType? {
42 | return fromJSON(value as? JSONType)
43 | }
44 |
45 | open func transformToJSON(_ value: ObjectType?) -> JSONType? {
46 | return toJSON(value)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/TransformType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransformType.swift
3 | // ObjectMapper
4 | //
5 | // Created by Syo Ikeda on 2/4/15.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | public protocol TransformType {
30 | associatedtype Object
31 | associatedtype JSON
32 |
33 | func transformFromJSON(_ value: Any?) -> Object?
34 | func transformToJSON(_ value: Object?) -> JSON?
35 | }
36 |
--------------------------------------------------------------------------------
/Pods/ObjectMapper/Sources/URLTransform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLTransform.swift
3 | // ObjectMapper
4 | //
5 | // Created by Tristan Himmelman on 2014-10-27.
6 | //
7 | // The MIT License (MIT)
8 | //
9 | // Copyright (c) 2014-2016 Hearst
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy
12 | // of this software and associated documentation files (the "Software"), to deal
13 | // in the Software without restriction, including without limitation the rights
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | // copies of the Software, and to permit persons to whom the Software is
16 | // furnished to do so, subject to the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be included in
19 | // all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | // THE SOFTWARE.
28 |
29 | import Foundation
30 |
31 | open class URLTransform: TransformType {
32 | public typealias Object = URL
33 | public typealias JSON = String
34 | private let shouldEncodeURLString: Bool
35 | private let allowedCharacterSet: CharacterSet
36 |
37 | /**
38 | Initializes the URLTransform with an option to encode URL strings before converting them to an NSURL
39 | - parameter shouldEncodeUrlString: when true (the default) the string is encoded before passing
40 | to `NSURL(string:)`
41 | - returns: an initialized transformer
42 | */
43 | public init(shouldEncodeURLString: Bool = true, allowedCharacterSet: CharacterSet = .urlQueryAllowed) {
44 | self.shouldEncodeURLString = shouldEncodeURLString
45 | self.allowedCharacterSet = allowedCharacterSet
46 | }
47 |
48 | open func transformFromJSON(_ value: Any?) -> URL? {
49 | guard let URLString = value as? String else { return nil }
50 |
51 | if !shouldEncodeURLString {
52 | return URL(string: URLString)
53 | }
54 |
55 | guard let escapedURLString = URLString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) else {
56 | return nil
57 | }
58 | return URL(string: escapedURLString)
59 | }
60 |
61 | open func transformToJSON(_ value: URL?) -> String? {
62 | if let URL = value {
63 | return URL.absoluteString
64 | }
65 | return nil
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Alamofire : NSObject
3 | @end
4 | @implementation PodsDummy_Alamofire
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double AlamofireVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire.modulemap:
--------------------------------------------------------------------------------
1 | framework module Alamofire {
2 | umbrella header "Alamofire-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/Alamofire.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Alamofire
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Alamofire/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 | 4.5.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/AlamofireObjectMapper-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_AlamofireObjectMapper : NSObject
3 | @end
4 | @implementation PodsDummy_AlamofireObjectMapper
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/AlamofireObjectMapper-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/AlamofireObjectMapper-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double AlamofireObjectMapperVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char AlamofireObjectMapperVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/AlamofireObjectMapper.modulemap:
--------------------------------------------------------------------------------
1 | framework module AlamofireObjectMapper {
2 | umbrella header "AlamofireObjectMapper-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/AlamofireObjectMapper.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/AlamofireObjectMapper
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/AlamofireObjectMapper
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/AlamofireObjectMapper/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 | 5.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/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 | 4.2.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Kingfisher : NSObject
3 | @end
4 | @implementation PodsDummy_Kingfisher
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "Kingfisher.h"
14 |
15 | FOUNDATION_EXPORT double KingfisherVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/Kingfisher.modulemap:
--------------------------------------------------------------------------------
1 | framework module Kingfisher {
2 | umbrella header "Kingfisher-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Kingfisher/Kingfisher.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Kingfisher
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_LDFLAGS = -framework "CFNetwork"
5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | SWIFT_VERSION = 4.0
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/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 | 3.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/ObjectMapper-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_ObjectMapper : NSObject
3 | @end
4 | @implementation PodsDummy_ObjectMapper
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/ObjectMapper-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/ObjectMapper-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double ObjectMapperVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char ObjectMapperVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/ObjectMapper.modulemap:
--------------------------------------------------------------------------------
1 | framework module ObjectMapper {
2 | umbrella header "ObjectMapper-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/ObjectMapper/ObjectMapper.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ObjectMapper
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ObjectMapper
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | SWIFT_VERSION = 4.0
12 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/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.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Alamofire
5 |
6 | Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 |
27 | ## AlamofireObjectMapper
28 |
29 | The MIT License (MIT)
30 |
31 | Copyright (c) 2015 Tristan Himmelman
32 |
33 | Permission is hereby granted, free of charge, to any person obtaining a copy
34 | of this software and associated documentation files (the "Software"), to deal
35 | in the Software without restriction, including without limitation the rights
36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37 | copies of the Software, and to permit persons to whom the Software is
38 | furnished to do so, subject to the following conditions:
39 |
40 | The above copyright notice and this permission notice shall be included in all
41 | copies or substantial portions of the Software.
42 |
43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49 | SOFTWARE.
50 |
51 |
52 |
53 | ## Kingfisher
54 |
55 | The MIT License (MIT)
56 |
57 | Copyright (c) 2017 Wei Wang
58 |
59 | Permission is hereby granted, free of charge, to any person obtaining a copy
60 | of this software and associated documentation files (the "Software"), to deal
61 | in the Software without restriction, including without limitation the rights
62 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63 | copies of the Software, and to permit persons to whom the Software is
64 | furnished to do so, subject to the following conditions:
65 |
66 | The above copyright notice and this permission notice shall be included in all
67 | copies or substantial portions of the Software.
68 |
69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
75 | SOFTWARE.
76 |
77 |
78 |
79 | ## ObjectMapper
80 |
81 | The MIT License (MIT)
82 | Copyright (c) 2014 Hearst
83 |
84 | 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:
85 |
86 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
87 |
88 | 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.
89 |
90 | Generated by CocoaPods - https://cocoapods.org
91 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_CleanArchitectureWithCoordinatorPatternDemo : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_CleanArchitectureWithCoordinatorPatternDemo
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_CleanArchitectureWithCoordinatorPatternDemoVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_CleanArchitectureWithCoordinatorPatternDemoVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/AlamofireObjectMapper" "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher" "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/AlamofireObjectMapper/AlamofireObjectMapper.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher/Kingfisher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper/ObjectMapper.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "Kingfisher" -framework "ObjectMapper"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_CleanArchitectureWithCoordinatorPatternDemo {
2 | umbrella header "Pods-CleanArchitectureWithCoordinatorPatternDemo-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-CleanArchitectureWithCoordinatorPatternDemo/Pods-CleanArchitectureWithCoordinatorPatternDemo.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/AlamofireObjectMapper" "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher" "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/AlamofireObjectMapper/AlamofireObjectMapper.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher/Kingfisher.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper/ObjectMapper.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "Kingfisher" -framework "ObjectMapper"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iOS Clean Architecture with Coordinator pattern
2 |
3 | When you decide to use clean architecture in your project, it is very tired create new modules, because you need create at least 5 files for each. Imagine that you need to create 6 modules...I was suffering this problem, and this is the reason why I've created this template. It's very useful for me and I hope that for you too.
4 |
5 | ## How to install
6 |
7 | ### Using script (easy)
8 | Only need execute this command in terminal: `sudo swift install.swift`
9 | You should be this output message:
10 | ************************************
11 | ✅ Xcode🔨 template installed succesfully 👌🏻. Enjoy it 👨🏻💻
12 | ************************************
13 |
14 | ## How to uninstall
15 |
16 | ### Using script (easy)
17 | Only need execute this command in terminal: `sudo swift uninstall.swift`
18 | You should be this output message:
19 |
20 | ************************************
21 | ✅ Xcode🔨 template uninstalled succesfully 👌🏻.
22 | ************************************
23 |
24 | If all it's ok you now could find your template in Xcode.
25 |
26 | ### Manual
27 | Go to Application folder, browse to the Xcode application icon. Right-click it and choose 'Show Package Contents'. Then browse to:
28 | `Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application` and add "Module VIP.xctemplate" file. Now you can find your template in Xcode.
29 |
30 |
31 | ## Generated code
32 | This template generates all files that you need to create a new clean module. All generated code is Swift 4.
33 |
34 | ## References
35 | - reference to my article
36 |
37 | ## Contributed
38 | This is an open source project, so feel free to contribute. How?
39 |
40 | - Open an [issue](link).
41 | - Send feedback via [email](maksimkn.94@gmail.com).
42 | - Propose your own fixes, suggestions and open a pull request with the changes.
43 |
44 | ## Author
45 |
46 | * Kazachkov Maksim
47 |
--------------------------------------------------------------------------------
/install.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // InstallVIPERTemplate
4 | //
5 | // Created by Juanpe Catalán on 17/02/2017.
6 | // Copyright © 2017 Juanpe Catalán. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | let templateName = "Module VIP.xctemplate"
12 | let destinationRelativePath = "/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application"
13 |
14 | func printInConsole(_ message:Any){
15 | print("\n")
16 | print("************************************")
17 | print("\(message)")
18 | print("************************************")
19 | }
20 |
21 | func moveTemplate(){
22 |
23 | let fileManager = FileManager.default
24 | let destinationPath = bash(command: "xcode-select", arguments: ["--print-path"]).appending(destinationRelativePath)
25 | do {
26 | if !fileManager.fileExists(atPath:"\(destinationPath)/\(templateName)"){
27 |
28 | try fileManager.copyItem(atPath: templateName, toPath: "\(destinationPath)/\(templateName)")
29 |
30 | printInConsole("✅ Xcode🔨 template installed succesfully 👌🏻. Enjoy it 👨🏻💻")
31 |
32 | }
33 | else {
34 | try _ = fileManager.replaceItemAt(URL(fileURLWithPath:"\(destinationPath)/\(templateName)"), withItemAt: URL(fileURLWithPath:templateName))
35 |
36 | printInConsole("✅ Xcode🔨 template already exists. So has been replaced succesfully 👌🏻. Enjoy it 👨🏻💻")
37 | }
38 | }
39 | catch let error as NSError {
40 | printInConsole("❌ Ooops! Something went wrong 🔥😡 : \(error.localizedFailureReason!)")
41 | }
42 | }
43 |
44 | func shell(launchPath: String, arguments: [String]) -> String
45 | {
46 | let task = Process()
47 | task.launchPath = launchPath
48 | task.arguments = arguments
49 |
50 | let pipe = Pipe()
51 | task.standardOutput = pipe
52 | task.launch()
53 |
54 | let data = pipe.fileHandleForReading.readDataToEndOfFile()
55 | let output = String(data: data, encoding: String.Encoding.utf8)!
56 | if output.characters.count > 0 {
57 | //remove newline character.
58 | let lastIndex = output.index(before: output.endIndex)
59 | return String(output[output.startIndex ..< lastIndex])
60 | }
61 | return output
62 | }
63 |
64 | func bash(command: String, arguments: [String]) -> String {
65 | let whichPathForCommand = shell(launchPath: "/bin/bash", arguments: [ "-l", "-c", "which \(command)" ])
66 | return shell(launchPath: whichPathForCommand, arguments: arguments)
67 | }
68 |
69 | moveTemplate()
70 |
--------------------------------------------------------------------------------
/uninstall.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // InstallVIPTemplate
4 | //
5 | // Created by Kazachkov Maksim on 29/10/2017.
6 | // Copyright © 2017 Kazachkov Maksim. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | let templateName = "Module VIP.xctemplate"
12 | let destinationRelativePath = "/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application"
13 |
14 | func printInConsole(_ message:Any){
15 | print("\n")
16 | print("************************************")
17 | print("\(message)")
18 | print("************************************")
19 | }
20 |
21 | func removeTemplate(){
22 |
23 | let fileManager = FileManager.default
24 | let destinationPath = bash(command: "xcode-select", arguments: ["--print-path"]).appending(destinationRelativePath)
25 | do {
26 | let path = "\(destinationPath)/\(templateName)"
27 | if fileManager.fileExists(atPath: path){
28 | try _ = fileManager.removeItem(atPath: "\(destinationPath)/\(templateName)")
29 | printInConsole("✅ Xcode🔨 template uninstalled succesfully 👌🏻.")
30 | }
31 | else {
32 | printInConsole("❌ Xcode🔨 template does not exist at \(path).")
33 | }
34 |
35 | }
36 | catch let error as NSError {
37 | printInConsole("❌ Ooops! Something went wrong 🔥😡 : \(error.localizedFailureReason!)")
38 | }
39 | }
40 |
41 | func shell(launchPath: String, arguments: [String]) -> String
42 | {
43 | let task = Process()
44 | task.launchPath = launchPath
45 | task.arguments = arguments
46 |
47 | let pipe = Pipe()
48 | task.standardOutput = pipe
49 | task.launch()
50 |
51 | let data = pipe.fileHandleForReading.readDataToEndOfFile()
52 | let output = String(data: data, encoding: String.Encoding.utf8)!
53 | if output.characters.count > 0 {
54 | //remove newline character.
55 | let lastIndex = output.index(before: output.endIndex)
56 | return String(output[output.startIndex ..< lastIndex])
57 | }
58 | return output
59 | }
60 |
61 | func bash(command: String, arguments: [String]) -> String {
62 | let whichPathForCommand = shell(launchPath: "/bin/bash", arguments: [ "-l", "-c", "which \(command)" ])
63 | return shell(launchPath: whichPathForCommand, arguments: arguments)
64 | }
65 |
66 | removeTemplate()
67 |
--------------------------------------------------------------------------------