├── .gitignore
├── Configs
├── RxModal.plist
└── RxModalTests.plist
├── LICENSE
├── Package.swift
├── README.md
├── RxModal.podspec
├── RxModal.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── RxModal-iOS.xcscheme
│ ├── RxModal-macOS.xcscheme
│ ├── RxModal-tvOS.xcscheme
│ └── RxModal-watchOS.xcscheme
├── RxModalExample
├── Podfile
├── Podfile.lock
├── RxModalExample.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── RxModalExample.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── swiftpm
│ │ └── Package.resolved
└── RxModalExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon.png
│ │ ├── icon_128pt.png
│ │ ├── icon_256pt-1.png
│ │ ├── icon_256pt.png
│ │ ├── icon_512pt-1.png
│ │ ├── icon_512pt.png
│ │ ├── icon_512pt@2x.png
│ │ ├── icon_60pt@2x.png
│ │ ├── icon_60pt@3x.png
│ │ ├── icon_76pt.png
│ │ ├── icon_76pt@2x.png
│ │ └── icon_83.5@2x.png
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Flow.swift
│ ├── FlowDetailViewController.swift
│ ├── FlowsListViewController.swift
│ ├── Info.plist
│ ├── RxModalExample.entitlements
│ └── SceneDelegate.swift
├── Sources
├── Composers
│ ├── MFMailComposeViewController.swift
│ └── MFMessageComposeViewController.swift
├── Dialogs
│ ├── Dialog.swift
│ └── UIAlertController.swift
├── Internals.swift
├── Other
│ └── ASWebAuthenticationSession.swift
├── Pickers
│ ├── MPMediaPickerController.swift
│ └── PHPickerViewController.swift
├── Presenter.swift
├── Rx+AuthorizationStatus.swift
├── RxModal.swift
├── RxModalCoordinator.swift
└── RxModalDescription.swift
├── Tests
├── LinuxMain.swift
└── RxModalTests
│ └── RxModalTests.swift
└── assets
├── RxModal_Demo.gif
└── RxModal_Icons.png
/.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 |
--------------------------------------------------------------------------------
/Configs/RxModal.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2021 Jérôme Alves. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Configs/RxModalTests.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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Jérôme Alves
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 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "RxModal",
8 | products: [
9 | .library(name: "RxModal", targets: ["RxModal"]),
10 | ],
11 | dependencies: [
12 | .package(url: "https://github.com/ReactiveX/RxSwift.git", .upToNextMajor(from: "6.0.0")),
13 | ],
14 | targets: [
15 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
16 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
17 | .target(
18 | name: "RxModal",
19 | dependencies: ["RxSwift", "RxCocoa"],
20 | path: "Sources"
21 | ),
22 | .testTarget(
23 | name: "RxModalTests",
24 | dependencies: ["RxModal"]
25 | ),
26 | ]
27 | )
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | # RxModal
9 |
10 | **RxModal** enforces the simple idea that a modal flow can be considered as a simple asynchroneous event:
11 | - the view controller is presented on subscribe
12 | - the user do what they want to do in the modal view
13 | - the view controller is dismissed on dispose and eventually emit a value or an error
14 |
15 | # Usage
16 |
17 |
18 |
19 | Here's an example |
20 | In Action |
21 |
22 |
23 |
24 | let mailComposer = RxModal.mailComposer {
25 | $0.setToRecipients([
26 | "rxmodal@rxswiftcommunity.org"
27 | ])
28 | $0.setMessageBody(
29 | "Hello World!",
30 | isHTML: false
31 | )
32 | }
33 | let messageComposer = RxModal.messageComposer {
34 | $0.recipients = ["0639981337"]
35 | $0.body = "Hello World!"
36 | }
37 | contactUsButton
38 | .rx.tap
39 | .flatMapFirst { [unowned contactUsButton] in
40 | RxModal.actionSheet(
41 | source: .bounds(contactUsButton),
42 | actions: [
43 | .default(
44 | title: "Mail",
45 | flatMapTo: mailComposer
46 | ),
47 | .default(
48 | title: "Message",
49 | flatMapTo: messageComposer
50 | ),
51 | .cancel(title: "Cancel")
52 | ])
53 | }
54 | .subscribe()
55 | .disposed(by: disposeBag)
56 |
57 | |
58 |
59 |
60 | |
61 |
62 |
63 |
64 | # Supported Modals
65 |
66 | ```swift
67 | // MFMailComposeViewController
68 | RxModal.mailComposer() -> Single
69 |
70 | // MFMessageComposeViewController
71 | RxModal.messageComposer() -> Single
72 |
73 | // MPMediaPickerController
74 | RxModal.mediaPicker() -> Single
75 |
76 | // PHPickerViewController
77 | RxModal.photoPicker() -> Single<[PHPickerResult]>
78 |
79 | // ASWebAuthenticationSession
80 | RxModal.webAuthenticationSession(url:callbackURLScheme:) -> Single
81 |
82 | // UIAlertController
83 | RxModal.alert(title:message:textFields:actions:) -> Observable
84 | RxModal.actionSheet(source:title:message:actions:) -> Observable
85 | ```
86 |
87 | ### Presenter
88 |
89 | All these functions also include a `presenter: Presenter` argument that allows you to choose where the modal will be presented.
90 | Presenters are just lazy `UIViewController` getters:
91 | ```swift
92 | .viewController(_:) -> $0
93 | .view(_:) -> $0.window?.rootViewController
94 | .window(_:) -> $0.rootViewController
95 | .scene(_:) -> $0.windows.first?.rootViewController
96 | .keyWindow -> UIApplication.shared.keyWindow?.rootViewController
97 | ```
98 | Default is `.keyWindow`. On iPad or macCatalyst allowing multiple windows, we discourage you to use `.keyWindow` or `.scene(_:)` as it might select the wrong window.
99 |
100 | ### Configuration
101 |
102 | These functions also include a configuration closure : `(ViewController) -> Void` that will let you configure the view controller before presentation.
103 |
104 | If a modal requires some parameters at `init` time, they will be part of the `RxModal` function (ex: `ASWebAuthenticationSession`, `UIAlertController`).
105 |
106 | ### Preconditions
107 |
108 | Some RxModals perform precondition checks before presenting the modal and emit a `RxModalError.unsupported` if they aren't fulfilled:
109 | - `RxModal.mailComposer()` → `MFMailComposeViewController.canSendMail()`
110 | - `RxModal.messageComposer()` → `MFMessageComposeViewController.canSendText()`
111 |
112 | Some RxModals perform an authorization status check before presenting the modal and either request authorization, or emit a `RxModalError.authorizationStatusDenied(Any)` if authorization is denied:
113 | - `RxModal.mediaPicker()` → `MPMediaLibrary.authorizationStatus()`
114 |
115 | ### Dialogs
116 |
117 | `RxModal.alert()` and `RxModal.actionSheet()` allows you to define actions that are converted to a new Observable stream, a value, or an error:
118 | ```swift
119 | DialogAction.default(title:flatMapTo: Observable)
120 | DialogAction.default(title:mapTo: T) // == flatMapTo: Observable.just(T)
121 | DialogAction.default(title:throw: Error) // == flatMapTo: Observable.error(Error)
122 | DialogAction.default(title:) // == flatMapTo: Observable.empty()
123 | ```
124 |
125 | `RxModal.alert()` also let you configure alert text fields:
126 | ```swift
127 | RxModal.alert(
128 | title: "Sign in",
129 | message: "Please sign in using your credentials",
130 | textFields: [
131 | DialogTextField.email { $0.placeholder = "e-mail" },
132 | DialogTextField.password { $0.placeholder = "password" }
133 | ],
134 | actions: [
135 | .cancel(title: "Cancel"),
136 | .default(title: "Sign In") { textFields in
137 | Credentials(
138 | email: textFields[0].text ?? "",
139 | password: textFields[1].text ?? ""
140 | )
141 | },
142 | ]
143 | )
144 | ```
145 |
146 | # Extending RxModal
147 |
148 | You can easily extend RxModal with your own controllers / modal flows.
149 |
150 | If your controller is already returning its output using Rx, it's easy:
151 | ```swift
152 | class MyModalViewController: UIViewController {
153 | let myResult = PublishSubject()
154 | // ...
155 | }
156 |
157 | extension RxModal {
158 | func myModal(
159 | presenter: Presenter = .keyWindow,
160 | configuration: @escaping (MyModalViewController) -> Void
161 | ) -> Single {
162 | RxModalCoordinator.present(using: presenter) { _ in
163 | let modal = MyModalViewController()
164 | configuration(modal)
165 | return modal
166 | } sequence: {
167 | $0.viewController.myResult.asSingle()
168 | }
169 | }
170 | }
171 | ```
172 |
173 | If your controller is rather using a traditional `delegate` approach, you'll need to subclass `RxModalCoordinator`:
174 |
175 | ```swift
176 | protocol MyModalViewControllerDelegate: AnyObject {
177 | func myModal(_ myModal: MyModalViewController, didFinishWith result: MyResult)
178 | func myModal(_ myModal: MyModalViewController, didFinishWithError error: Error)
179 | }
180 |
181 | class MyModalViewController: UIViewController {
182 | weak var delegate: MyModalViewControllerDelegate?
183 | // ...
184 | }
185 |
186 | extension RxModal {
187 | func myModal(
188 | presenter: Presenter = .keyWindow,
189 | configuration: @escaping (MyModalViewController) -> Void
190 | ) -> Single {
191 |
192 | MyModalViewControllerCoordinator.present(using: presenter) { coordinator in
193 | let modal = MyModalViewController()
194 | modal.delegate = coordinator
195 | configuration(modal)
196 | return modal
197 | } sequence: {
198 | $0.myResult.asSingle()
199 | }
200 |
201 | }
202 | }
203 |
204 | final class MyModalViewControllerCoordinator: RxModalCoordinator, MyModalViewControllerDelegate {
205 | required init(){}
206 |
207 | let myResult = PublishSubject()
208 |
209 | func myModal(_ myModal: MyModalViewController, didFinishWith result: MyResult) {
210 | myResult.onNext(result)
211 | myResult.onCompleted()
212 | }
213 |
214 | func myModal(_ myModal: MyModalViewController, didFinishWithError error: Error) {
215 | myResult.onError(error)
216 | }
217 |
218 | }
219 | ```
220 |
221 | If your controller is embedded in a non `UIViewController` object, you won't be able to leverage on `RxModalCoordinator` and you'll need to handle all the present/dismiss boilerplate. See [ASWebAuthenticationSession.swift](./Sources/Other/ASWebAuthenticationSession.swift) as an example.
222 |
223 |
224 | # Author
225 |
226 | [Jérôme Alves](https://twitter.com/jegnux)
227 |
228 | # License
229 |
230 | **RxModal** is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
231 |
--------------------------------------------------------------------------------
/RxModal.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "RxModal"
3 | s.version = "1.0.2"
4 | s.summary = "Subscribe to your modal flows"
5 | s.description = <<-DESC
6 | RxModal helps you handle any modal flow as a simple Observable sequence.
7 | DESC
8 | s.homepage = "https://github.com/RxSwiftCommunity/RxModal"
9 | s.license = { :type => "MIT", :file => "LICENSE" }
10 | s.author = { "Jérôme Alves" => "j.alves@me.com" }
11 | s.social_media_url = "https://twitter.com/jegnux"
12 | s.ios.deployment_target = '9.0'
13 | s.source = { :git => "https://github.com/RxSwiftCommunity/RxModal.git", :tag => s.version.to_s }
14 | s.source_files = "Sources/**/*"
15 | s.frameworks = "Foundation"
16 |
17 | s.dependency 'RxSwift', '~> 6.0'
18 | s.dependency 'RxCocoa', '~> 6.0'
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 47;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 52D6D9871BEFF229002C0205 /* RxModal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* RxModal.framework */; };
11 | 755A90E125D587490068D559 /* Internals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D325D587490068D559 /* Internals.swift */; };
12 | 755A90E225D587490068D559 /* RxModalDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D425D587490068D559 /* RxModalDescription.swift */; };
13 | 755A90E325D587490068D559 /* RxModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D525D587490068D559 /* RxModal.swift */; };
14 | 755A90E425D587490068D559 /* ASWebAuthenticationSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D725D587490068D559 /* ASWebAuthenticationSession.swift */; };
15 | 755A90E525D587490068D559 /* Rx+AuthorizationStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D825D587490068D559 /* Rx+AuthorizationStatus.swift */; };
16 | 755A90E625D587490068D559 /* Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90D925D587490068D559 /* Presenter.swift */; };
17 | 755A90E725D587490068D559 /* UIAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90DB25D587490068D559 /* UIAlertController.swift */; };
18 | 755A90E825D587490068D559 /* Dialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90DC25D587490068D559 /* Dialog.swift */; };
19 | 755A90E925D587490068D559 /* PHPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90DE25D587490068D559 /* PHPickerViewController.swift */; };
20 | 755A90EA25D587490068D559 /* MPMediaPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90DF25D587490068D559 /* MPMediaPickerController.swift */; };
21 | 755A90EB25D587490068D559 /* RxModalCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A90E025D587490068D559 /* RxModalCoordinator.swift */; };
22 | 75F1131D25D66E4E0005DACB /* MFMessageComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F1131B25D66E4E0005DACB /* MFMessageComposeViewController.swift */; };
23 | 75F1131E25D66E4E0005DACB /* MFMailComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F1131C25D66E4E0005DACB /* MFMailComposeViewController.swift */; };
24 | 8933C7901EB5B82D000D00A4 /* RxModalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7891EB5B82A000D00A4 /* RxModalTests.swift */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXContainerItemProxy section */
28 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
31 | proxyType = 1;
32 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205;
33 | remoteInfo = RxModal;
34 | };
35 | /* End PBXContainerItemProxy section */
36 |
37 | /* Begin PBXFileReference section */
38 | 52D6D97C1BEFF229002C0205 /* RxModal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxModal.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 52D6D9861BEFF229002C0205 /* RxModal-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "RxModal-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 755A90D325D587490068D559 /* Internals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Internals.swift; sourceTree = ""; };
41 | 755A90D425D587490068D559 /* RxModalDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxModalDescription.swift; sourceTree = ""; };
42 | 755A90D525D587490068D559 /* RxModal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxModal.swift; sourceTree = ""; };
43 | 755A90D725D587490068D559 /* ASWebAuthenticationSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASWebAuthenticationSession.swift; sourceTree = ""; };
44 | 755A90D825D587490068D559 /* Rx+AuthorizationStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Rx+AuthorizationStatus.swift"; sourceTree = ""; };
45 | 755A90D925D587490068D559 /* Presenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Presenter.swift; sourceTree = ""; };
46 | 755A90DB25D587490068D559 /* UIAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIAlertController.swift; sourceTree = ""; };
47 | 755A90DC25D587490068D559 /* Dialog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dialog.swift; sourceTree = ""; };
48 | 755A90DE25D587490068D559 /* PHPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PHPickerViewController.swift; sourceTree = ""; };
49 | 755A90DF25D587490068D559 /* MPMediaPickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MPMediaPickerController.swift; sourceTree = ""; };
50 | 755A90E025D587490068D559 /* RxModalCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxModalCoordinator.swift; sourceTree = ""; };
51 | 75F1131B25D66E4E0005DACB /* MFMessageComposeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFMessageComposeViewController.swift; sourceTree = ""; };
52 | 75F1131C25D66E4E0005DACB /* MFMailComposeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFMailComposeViewController.swift; sourceTree = ""; };
53 | 8933C7891EB5B82A000D00A4 /* RxModalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxModalTests.swift; sourceTree = ""; };
54 | AD2FAA261CD0B6D800659CF4 /* RxModal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = RxModal.plist; sourceTree = ""; };
55 | AD2FAA281CD0B6E100659CF4 /* RxModalTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = RxModalTests.plist; sourceTree = ""; };
56 | /* End PBXFileReference section */
57 |
58 | /* Begin PBXFrameworksBuildPhase section */
59 | 52D6D9781BEFF229002C0205 /* Frameworks */ = {
60 | isa = PBXFrameworksBuildPhase;
61 | buildActionMask = 2147483647;
62 | files = (
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | 52D6D9831BEFF229002C0205 /* Frameworks */ = {
67 | isa = PBXFrameworksBuildPhase;
68 | buildActionMask = 2147483647;
69 | files = (
70 | 52D6D9871BEFF229002C0205 /* RxModal.framework in Frameworks */,
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | /* End PBXFrameworksBuildPhase section */
75 |
76 | /* Begin PBXGroup section */
77 | 52D6D9721BEFF229002C0205 = {
78 | isa = PBXGroup;
79 | children = (
80 | 755A90D225D587490068D559 /* Sources */,
81 | 8933C7831EB5B7EB000D00A4 /* Tests */,
82 | 52D6D99C1BEFF38C002C0205 /* Configs */,
83 | 52D6D97D1BEFF229002C0205 /* Products */,
84 | );
85 | sourceTree = "";
86 | };
87 | 52D6D97D1BEFF229002C0205 /* Products */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 52D6D97C1BEFF229002C0205 /* RxModal.framework */,
91 | 52D6D9861BEFF229002C0205 /* RxModal-iOS Tests.xctest */,
92 | );
93 | name = Products;
94 | sourceTree = "";
95 | };
96 | 52D6D99C1BEFF38C002C0205 /* Configs */ = {
97 | isa = PBXGroup;
98 | children = (
99 | DD7502721C68FC1B006590AF /* Frameworks */,
100 | DD7502731C68FC20006590AF /* Tests */,
101 | );
102 | path = Configs;
103 | sourceTree = "";
104 | };
105 | 755A90D225D587490068D559 /* Sources */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 755A90D325D587490068D559 /* Internals.swift */,
109 | 755A90D525D587490068D559 /* RxModal.swift */,
110 | 755A90D425D587490068D559 /* RxModalDescription.swift */,
111 | 755A90E025D587490068D559 /* RxModalCoordinator.swift */,
112 | 755A90D825D587490068D559 /* Rx+AuthorizationStatus.swift */,
113 | 755A90D925D587490068D559 /* Presenter.swift */,
114 | 755A90D625D587490068D559 /* Other */,
115 | 755A90DA25D587490068D559 /* Dialogs */,
116 | 755A90DD25D587490068D559 /* Pickers */,
117 | 75F1131A25D66E4E0005DACB /* Composers */,
118 | );
119 | path = Sources;
120 | sourceTree = "";
121 | };
122 | 755A90D625D587490068D559 /* Other */ = {
123 | isa = PBXGroup;
124 | children = (
125 | 755A90D725D587490068D559 /* ASWebAuthenticationSession.swift */,
126 | );
127 | path = Other;
128 | sourceTree = "";
129 | };
130 | 755A90DA25D587490068D559 /* Dialogs */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 755A90DB25D587490068D559 /* UIAlertController.swift */,
134 | 755A90DC25D587490068D559 /* Dialog.swift */,
135 | );
136 | path = Dialogs;
137 | sourceTree = "";
138 | };
139 | 755A90DD25D587490068D559 /* Pickers */ = {
140 | isa = PBXGroup;
141 | children = (
142 | 755A90DE25D587490068D559 /* PHPickerViewController.swift */,
143 | 755A90DF25D587490068D559 /* MPMediaPickerController.swift */,
144 | );
145 | path = Pickers;
146 | sourceTree = "";
147 | };
148 | 75F1131A25D66E4E0005DACB /* Composers */ = {
149 | isa = PBXGroup;
150 | children = (
151 | 75F1131B25D66E4E0005DACB /* MFMessageComposeViewController.swift */,
152 | 75F1131C25D66E4E0005DACB /* MFMailComposeViewController.swift */,
153 | );
154 | path = Composers;
155 | sourceTree = "";
156 | };
157 | 8933C7831EB5B7EB000D00A4 /* Tests */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 8933C7891EB5B82A000D00A4 /* RxModalTests.swift */,
161 | );
162 | name = Tests;
163 | path = Tests/RxModalTests;
164 | sourceTree = "";
165 | };
166 | DD7502721C68FC1B006590AF /* Frameworks */ = {
167 | isa = PBXGroup;
168 | children = (
169 | AD2FAA261CD0B6D800659CF4 /* RxModal.plist */,
170 | );
171 | name = Frameworks;
172 | sourceTree = "";
173 | };
174 | DD7502731C68FC20006590AF /* Tests */ = {
175 | isa = PBXGroup;
176 | children = (
177 | AD2FAA281CD0B6E100659CF4 /* RxModalTests.plist */,
178 | );
179 | name = Tests;
180 | sourceTree = "";
181 | };
182 | /* End PBXGroup section */
183 |
184 | /* Begin PBXHeadersBuildPhase section */
185 | 52D6D9791BEFF229002C0205 /* Headers */ = {
186 | isa = PBXHeadersBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | );
190 | runOnlyForDeploymentPostprocessing = 0;
191 | };
192 | /* End PBXHeadersBuildPhase section */
193 |
194 | /* Begin PBXNativeTarget section */
195 | 52D6D97B1BEFF229002C0205 /* RxModal-iOS */ = {
196 | isa = PBXNativeTarget;
197 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "RxModal-iOS" */;
198 | buildPhases = (
199 | 52D6D9771BEFF229002C0205 /* Sources */,
200 | 52D6D9781BEFF229002C0205 /* Frameworks */,
201 | 52D6D9791BEFF229002C0205 /* Headers */,
202 | 52D6D97A1BEFF229002C0205 /* Resources */,
203 | );
204 | buildRules = (
205 | );
206 | dependencies = (
207 | );
208 | name = "RxModal-iOS";
209 | productName = RxModal;
210 | productReference = 52D6D97C1BEFF229002C0205 /* RxModal.framework */;
211 | productType = "com.apple.product-type.framework";
212 | };
213 | 52D6D9851BEFF229002C0205 /* RxModal-iOS Tests */ = {
214 | isa = PBXNativeTarget;
215 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "RxModal-iOS Tests" */;
216 | buildPhases = (
217 | 52D6D9821BEFF229002C0205 /* Sources */,
218 | 52D6D9831BEFF229002C0205 /* Frameworks */,
219 | 52D6D9841BEFF229002C0205 /* Resources */,
220 | );
221 | buildRules = (
222 | );
223 | dependencies = (
224 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */,
225 | );
226 | name = "RxModal-iOS Tests";
227 | productName = RxModalTests;
228 | productReference = 52D6D9861BEFF229002C0205 /* RxModal-iOS Tests.xctest */;
229 | productType = "com.apple.product-type.bundle.unit-test";
230 | };
231 | /* End PBXNativeTarget section */
232 |
233 | /* Begin PBXProject section */
234 | 52D6D9731BEFF229002C0205 /* Project object */ = {
235 | isa = PBXProject;
236 | attributes = {
237 | LastSwiftUpdateCheck = 0720;
238 | LastUpgradeCheck = 1020;
239 | ORGANIZATIONNAME = RxSwiftCommunity;
240 | TargetAttributes = {
241 | 52D6D97B1BEFF229002C0205 = {
242 | CreatedOnToolsVersion = 7.1;
243 | LastSwiftMigration = 1020;
244 | };
245 | 52D6D9851BEFF229002C0205 = {
246 | CreatedOnToolsVersion = 7.1;
247 | LastSwiftMigration = 1020;
248 | };
249 | };
250 | };
251 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "RxModal" */;
252 | compatibilityVersion = "Xcode 6.3";
253 | developmentRegion = en;
254 | hasScannedForEncodings = 0;
255 | knownRegions = (
256 | en,
257 | Base,
258 | );
259 | mainGroup = 52D6D9721BEFF229002C0205;
260 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */;
261 | projectDirPath = "";
262 | projectRoot = "";
263 | targets = (
264 | 52D6D97B1BEFF229002C0205 /* RxModal-iOS */,
265 | 52D6D9851BEFF229002C0205 /* RxModal-iOS Tests */,
266 | );
267 | };
268 | /* End PBXProject section */
269 |
270 | /* Begin PBXResourcesBuildPhase section */
271 | 52D6D97A1BEFF229002C0205 /* Resources */ = {
272 | isa = PBXResourcesBuildPhase;
273 | buildActionMask = 2147483647;
274 | files = (
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | 52D6D9841BEFF229002C0205 /* Resources */ = {
279 | isa = PBXResourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | );
283 | runOnlyForDeploymentPostprocessing = 0;
284 | };
285 | /* End PBXResourcesBuildPhase section */
286 |
287 | /* Begin PBXSourcesBuildPhase section */
288 | 52D6D9771BEFF229002C0205 /* Sources */ = {
289 | isa = PBXSourcesBuildPhase;
290 | buildActionMask = 2147483647;
291 | files = (
292 | 755A90E625D587490068D559 /* Presenter.swift in Sources */,
293 | 75F1131E25D66E4E0005DACB /* MFMailComposeViewController.swift in Sources */,
294 | 755A90E225D587490068D559 /* RxModalDescription.swift in Sources */,
295 | 755A90E125D587490068D559 /* Internals.swift in Sources */,
296 | 755A90EB25D587490068D559 /* RxModalCoordinator.swift in Sources */,
297 | 75F1131D25D66E4E0005DACB /* MFMessageComposeViewController.swift in Sources */,
298 | 755A90EA25D587490068D559 /* MPMediaPickerController.swift in Sources */,
299 | 755A90E725D587490068D559 /* UIAlertController.swift in Sources */,
300 | 755A90E525D587490068D559 /* Rx+AuthorizationStatus.swift in Sources */,
301 | 755A90E425D587490068D559 /* ASWebAuthenticationSession.swift in Sources */,
302 | 755A90E325D587490068D559 /* RxModal.swift in Sources */,
303 | 755A90E825D587490068D559 /* Dialog.swift in Sources */,
304 | 755A90E925D587490068D559 /* PHPickerViewController.swift in Sources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | 52D6D9821BEFF229002C0205 /* Sources */ = {
309 | isa = PBXSourcesBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | 8933C7901EB5B82D000D00A4 /* RxModalTests.swift in Sources */,
313 | );
314 | runOnlyForDeploymentPostprocessing = 0;
315 | };
316 | /* End PBXSourcesBuildPhase section */
317 |
318 | /* Begin PBXTargetDependency section */
319 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = {
320 | isa = PBXTargetDependency;
321 | target = 52D6D97B1BEFF229002C0205 /* RxModal-iOS */;
322 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */;
323 | };
324 | /* End PBXTargetDependency section */
325 |
326 | /* Begin XCBuildConfiguration section */
327 | 52D6D98E1BEFF229002C0205 /* Debug */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ALWAYS_SEARCH_USER_PATHS = NO;
331 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
333 | CLANG_CXX_LIBRARY = "libc++";
334 | CLANG_ENABLE_MODULES = YES;
335 | CLANG_ENABLE_OBJC_ARC = YES;
336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
337 | CLANG_WARN_BOOL_CONVERSION = YES;
338 | CLANG_WARN_COMMA = YES;
339 | CLANG_WARN_CONSTANT_CONVERSION = YES;
340 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
342 | CLANG_WARN_EMPTY_BODY = YES;
343 | CLANG_WARN_ENUM_CONVERSION = YES;
344 | CLANG_WARN_INFINITE_RECURSION = YES;
345 | CLANG_WARN_INT_CONVERSION = YES;
346 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
347 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
348 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
350 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
351 | CLANG_WARN_STRICT_PROTOTYPES = YES;
352 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
353 | CLANG_WARN_UNREACHABLE_CODE = YES;
354 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
355 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
356 | COPY_PHASE_STRIP = NO;
357 | CURRENT_PROJECT_VERSION = 1;
358 | DEBUG_INFORMATION_FORMAT = dwarf;
359 | ENABLE_STRICT_OBJC_MSGSEND = YES;
360 | ENABLE_TESTABILITY = YES;
361 | GCC_C_LANGUAGE_STANDARD = gnu99;
362 | GCC_DYNAMIC_NO_PIC = NO;
363 | GCC_NO_COMMON_BLOCKS = YES;
364 | GCC_OPTIMIZATION_LEVEL = 0;
365 | GCC_PREPROCESSOR_DEFINITIONS = (
366 | "DEBUG=1",
367 | "$(inherited)",
368 | );
369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
371 | GCC_WARN_UNDECLARED_SELECTOR = YES;
372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
373 | GCC_WARN_UNUSED_FUNCTION = YES;
374 | GCC_WARN_UNUSED_VARIABLE = YES;
375 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
376 | MTL_ENABLE_DEBUG_INFO = YES;
377 | ONLY_ACTIVE_ARCH = YES;
378 | SDKROOT = iphoneos;
379 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
380 | SWIFT_VERSION = 5.0;
381 | TARGETED_DEVICE_FAMILY = "1,2";
382 | VERSIONING_SYSTEM = "apple-generic";
383 | VERSION_INFO_PREFIX = "";
384 | };
385 | name = Debug;
386 | };
387 | 52D6D98F1BEFF229002C0205 /* Release */ = {
388 | isa = XCBuildConfiguration;
389 | buildSettings = {
390 | ALWAYS_SEARCH_USER_PATHS = NO;
391 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
393 | CLANG_CXX_LIBRARY = "libc++";
394 | CLANG_ENABLE_MODULES = YES;
395 | CLANG_ENABLE_OBJC_ARC = YES;
396 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
397 | CLANG_WARN_BOOL_CONVERSION = YES;
398 | CLANG_WARN_COMMA = YES;
399 | CLANG_WARN_CONSTANT_CONVERSION = YES;
400 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
401 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
402 | CLANG_WARN_EMPTY_BODY = YES;
403 | CLANG_WARN_ENUM_CONVERSION = YES;
404 | CLANG_WARN_INFINITE_RECURSION = YES;
405 | CLANG_WARN_INT_CONVERSION = YES;
406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
411 | CLANG_WARN_STRICT_PROTOTYPES = YES;
412 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
413 | CLANG_WARN_UNREACHABLE_CODE = YES;
414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
415 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
416 | COPY_PHASE_STRIP = NO;
417 | CURRENT_PROJECT_VERSION = 1;
418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
419 | ENABLE_NS_ASSERTIONS = NO;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | GCC_C_LANGUAGE_STANDARD = gnu99;
422 | GCC_NO_COMMON_BLOCKS = YES;
423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
425 | GCC_WARN_UNDECLARED_SELECTOR = YES;
426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
427 | GCC_WARN_UNUSED_FUNCTION = YES;
428 | GCC_WARN_UNUSED_VARIABLE = YES;
429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
430 | MTL_ENABLE_DEBUG_INFO = NO;
431 | SDKROOT = iphoneos;
432 | SWIFT_VERSION = 5.0;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | VALIDATE_PRODUCT = YES;
435 | VERSIONING_SYSTEM = "apple-generic";
436 | VERSION_INFO_PREFIX = "";
437 | };
438 | name = Release;
439 | };
440 | 52D6D9911BEFF229002C0205 /* Debug */ = {
441 | isa = XCBuildConfiguration;
442 | buildSettings = {
443 | APPLICATION_EXTENSION_API_ONLY = YES;
444 | CLANG_ENABLE_MODULES = YES;
445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
446 | DEFINES_MODULE = YES;
447 | DYLIB_COMPATIBILITY_VERSION = 1;
448 | DYLIB_CURRENT_VERSION = 1;
449 | DYLIB_INSTALL_NAME_BASE = "@rpath";
450 | INFOPLIST_FILE = Configs/RxModal.plist;
451 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
453 | ONLY_ACTIVE_ARCH = NO;
454 | PRODUCT_BUNDLE_IDENTIFIER = "com.RxModal.RxModal-iOS";
455 | PRODUCT_NAME = RxModal;
456 | SKIP_INSTALL = YES;
457 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
458 | SWIFT_VERSION = 5.0;
459 | };
460 | name = Debug;
461 | };
462 | 52D6D9921BEFF229002C0205 /* Release */ = {
463 | isa = XCBuildConfiguration;
464 | buildSettings = {
465 | APPLICATION_EXTENSION_API_ONLY = YES;
466 | CLANG_ENABLE_MODULES = YES;
467 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
468 | DEFINES_MODULE = YES;
469 | DYLIB_COMPATIBILITY_VERSION = 1;
470 | DYLIB_CURRENT_VERSION = 1;
471 | DYLIB_INSTALL_NAME_BASE = "@rpath";
472 | INFOPLIST_FILE = Configs/RxModal.plist;
473 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
475 | PRODUCT_BUNDLE_IDENTIFIER = "com.RxModal.RxModal-iOS";
476 | PRODUCT_NAME = RxModal;
477 | SKIP_INSTALL = YES;
478 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
479 | SWIFT_VERSION = 5.0;
480 | };
481 | name = Release;
482 | };
483 | 52D6D9941BEFF229002C0205 /* Debug */ = {
484 | isa = XCBuildConfiguration;
485 | buildSettings = {
486 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
487 | CLANG_ENABLE_MODULES = YES;
488 | INFOPLIST_FILE = Configs/RxModalTests.plist;
489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
490 | PRODUCT_BUNDLE_IDENTIFIER = "com.RxModal.RxModal-iOS-Tests";
491 | PRODUCT_NAME = "$(TARGET_NAME)";
492 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
493 | SWIFT_VERSION = 5.0;
494 | };
495 | name = Debug;
496 | };
497 | 52D6D9951BEFF229002C0205 /* Release */ = {
498 | isa = XCBuildConfiguration;
499 | buildSettings = {
500 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
501 | CLANG_ENABLE_MODULES = YES;
502 | INFOPLIST_FILE = Configs/RxModalTests.plist;
503 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
504 | PRODUCT_BUNDLE_IDENTIFIER = "com.RxModal.RxModal-iOS-Tests";
505 | PRODUCT_NAME = "$(TARGET_NAME)";
506 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
507 | SWIFT_VERSION = 5.0;
508 | };
509 | name = Release;
510 | };
511 | /* End XCBuildConfiguration section */
512 |
513 | /* Begin XCConfigurationList section */
514 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "RxModal" */ = {
515 | isa = XCConfigurationList;
516 | buildConfigurations = (
517 | 52D6D98E1BEFF229002C0205 /* Debug */,
518 | 52D6D98F1BEFF229002C0205 /* Release */,
519 | );
520 | defaultConfigurationIsVisible = 0;
521 | defaultConfigurationName = Release;
522 | };
523 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "RxModal-iOS" */ = {
524 | isa = XCConfigurationList;
525 | buildConfigurations = (
526 | 52D6D9911BEFF229002C0205 /* Debug */,
527 | 52D6D9921BEFF229002C0205 /* Release */,
528 | );
529 | defaultConfigurationIsVisible = 0;
530 | defaultConfigurationName = Release;
531 | };
532 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "RxModal-iOS Tests" */ = {
533 | isa = XCConfigurationList;
534 | buildConfigurations = (
535 | 52D6D9941BEFF229002C0205 /* Debug */,
536 | 52D6D9951BEFF229002C0205 /* Release */,
537 | );
538 | defaultConfigurationIsVisible = 0;
539 | defaultConfigurationName = Release;
540 | };
541 | /* End XCConfigurationList section */
542 | };
543 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */;
544 | }
545 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/xcshareddata/xcschemes/RxModal-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/xcshareddata/xcschemes/RxModal-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/xcshareddata/xcschemes/RxModal-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/RxModal.xcodeproj/xcshareddata/xcschemes/RxModal-watchOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
71 |
72 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/RxModalExample/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'RxModalExample' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for RxModalExample
9 | pod 'RxModal', path: '../RxModal.podspec'
10 | end
11 |
--------------------------------------------------------------------------------
/RxModalExample/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - RxCocoa (6.0.0):
3 | - RxRelay (= 6.0.0)
4 | - RxSwift (= 6.0.0)
5 | - RxModal (1.0.1):
6 | - RxCocoa (~> 6.0)
7 | - RxSwift (~> 6.0)
8 | - RxRelay (6.0.0):
9 | - RxSwift (= 6.0.0)
10 | - RxSwift (6.0.0)
11 |
12 | DEPENDENCIES:
13 | - RxModal (from `../RxModal.podspec`)
14 |
15 | SPEC REPOS:
16 | trunk:
17 | - RxCocoa
18 | - RxRelay
19 | - RxSwift
20 |
21 | EXTERNAL SOURCES:
22 | RxModal:
23 | :path: "../RxModal.podspec"
24 |
25 | SPEC CHECKSUMS:
26 | RxCocoa: 3f79328fafa3645b34600f37c31e64c73ae3a80e
27 | RxModal: abfd791d24d9bba2539d6fe1f1a179dba8170e1d
28 | RxRelay: 8d593be109c06ea850df027351beba614b012ffb
29 | RxSwift: c14e798c59b9f6e9a2df8fd235602e85cc044295
30 |
31 | PODFILE CHECKSUM: 57ce72de39d50c403818fe31c9311026bd4a55fe
32 |
33 | COCOAPODS: 1.10.1
34 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1B0BC9AB78EE118468A1EC67 /* Pods_RxModalExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89B5467EFFDD600E8E0ECDA2 /* Pods_RxModalExample.framework */; };
11 | 7580E40325CB49A800F9A0A7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7580E40225CB49A800F9A0A7 /* AppDelegate.swift */; };
12 | 7580E40525CB49A800F9A0A7 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7580E40425CB49A800F9A0A7 /* SceneDelegate.swift */; };
13 | 7580E40725CB49A800F9A0A7 /* FlowsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7580E40625CB49A800F9A0A7 /* FlowsListViewController.swift */; };
14 | 7580E40A25CB49A800F9A0A7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7580E40825CB49A800F9A0A7 /* Main.storyboard */; };
15 | 7580E40C25CB49A900F9A0A7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7580E40B25CB49A900F9A0A7 /* Assets.xcassets */; };
16 | 7580E40F25CB49A900F9A0A7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7580E40D25CB49A900F9A0A7 /* LaunchScreen.storyboard */; };
17 | 75D9706325D5438900EECC2B /* Splash in Frameworks */ = {isa = PBXBuildFile; productRef = 75D9706225D5438900EECC2B /* Splash */; };
18 | 75D9706625D5716000EECC2B /* FlowDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D9706525D5716000EECC2B /* FlowDetailViewController.swift */; };
19 | 75D9706925D571C600EECC2B /* Flow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D9706825D571C600EECC2B /* Flow.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 225B62DC46C283E24EADD0CE /* Pods-RxModalExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxModalExample.release.xcconfig"; path = "Target Support Files/Pods-RxModalExample/Pods-RxModalExample.release.xcconfig"; sourceTree = ""; };
24 | 7580E3FF25CB49A800F9A0A7 /* RxModalExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxModalExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | 7580E40225CB49A800F9A0A7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
26 | 7580E40425CB49A800F9A0A7 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
27 | 7580E40625CB49A800F9A0A7 /* FlowsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowsListViewController.swift; sourceTree = ""; };
28 | 7580E40925CB49A800F9A0A7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
29 | 7580E40B25CB49A900F9A0A7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | 7580E40E25CB49A900F9A0A7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
31 | 7580E41025CB49A900F9A0A7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 75BA90C325CED7BA00AF94E6 /* RxModalExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RxModalExample.entitlements; sourceTree = ""; };
33 | 75D9706525D5716000EECC2B /* FlowDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowDetailViewController.swift; sourceTree = ""; };
34 | 75D9706825D571C600EECC2B /* Flow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flow.swift; sourceTree = ""; };
35 | 89B5467EFFDD600E8E0ECDA2 /* Pods_RxModalExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxModalExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
36 | A8FF776624B518F974CE128B /* Pods-RxModalExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxModalExample.debug.xcconfig"; path = "Target Support Files/Pods-RxModalExample/Pods-RxModalExample.debug.xcconfig"; sourceTree = ""; };
37 | /* End PBXFileReference section */
38 |
39 | /* Begin PBXFrameworksBuildPhase section */
40 | 7580E3FC25CB49A800F9A0A7 /* Frameworks */ = {
41 | isa = PBXFrameworksBuildPhase;
42 | buildActionMask = 2147483647;
43 | files = (
44 | 1B0BC9AB78EE118468A1EC67 /* Pods_RxModalExample.framework in Frameworks */,
45 | 75D9706325D5438900EECC2B /* Splash in Frameworks */,
46 | );
47 | runOnlyForDeploymentPostprocessing = 0;
48 | };
49 | /* End PBXFrameworksBuildPhase section */
50 |
51 | /* Begin PBXGroup section */
52 | 31F34B4B17BEF8787CAA7124 /* Pods */ = {
53 | isa = PBXGroup;
54 | children = (
55 | A8FF776624B518F974CE128B /* Pods-RxModalExample.debug.xcconfig */,
56 | 225B62DC46C283E24EADD0CE /* Pods-RxModalExample.release.xcconfig */,
57 | );
58 | path = Pods;
59 | sourceTree = "";
60 | };
61 | 7580E3F625CB49A800F9A0A7 = {
62 | isa = PBXGroup;
63 | children = (
64 | 7580E40125CB49A800F9A0A7 /* RxModalExample */,
65 | 7580E40025CB49A800F9A0A7 /* Products */,
66 | 31F34B4B17BEF8787CAA7124 /* Pods */,
67 | 94219E9B0A6AD0135DCD89B8 /* Frameworks */,
68 | );
69 | sourceTree = "";
70 | };
71 | 7580E40025CB49A800F9A0A7 /* Products */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 7580E3FF25CB49A800F9A0A7 /* RxModalExample.app */,
75 | );
76 | name = Products;
77 | sourceTree = "";
78 | };
79 | 7580E40125CB49A800F9A0A7 /* RxModalExample */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 75BA90C325CED7BA00AF94E6 /* RxModalExample.entitlements */,
83 | 7580E40225CB49A800F9A0A7 /* AppDelegate.swift */,
84 | 7580E40425CB49A800F9A0A7 /* SceneDelegate.swift */,
85 | 75D9706825D571C600EECC2B /* Flow.swift */,
86 | 7580E40625CB49A800F9A0A7 /* FlowsListViewController.swift */,
87 | 75D9706525D5716000EECC2B /* FlowDetailViewController.swift */,
88 | 7580E40825CB49A800F9A0A7 /* Main.storyboard */,
89 | 7580E40B25CB49A900F9A0A7 /* Assets.xcassets */,
90 | 7580E40D25CB49A900F9A0A7 /* LaunchScreen.storyboard */,
91 | 7580E41025CB49A900F9A0A7 /* Info.plist */,
92 | );
93 | path = RxModalExample;
94 | sourceTree = "";
95 | };
96 | 94219E9B0A6AD0135DCD89B8 /* Frameworks */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 89B5467EFFDD600E8E0ECDA2 /* Pods_RxModalExample.framework */,
100 | );
101 | name = Frameworks;
102 | sourceTree = "";
103 | };
104 | /* End PBXGroup section */
105 |
106 | /* Begin PBXNativeTarget section */
107 | 7580E3FE25CB49A800F9A0A7 /* RxModalExample */ = {
108 | isa = PBXNativeTarget;
109 | buildConfigurationList = 7580E41325CB49A900F9A0A7 /* Build configuration list for PBXNativeTarget "RxModalExample" */;
110 | buildPhases = (
111 | 3E3353F6ABD85963532BD1ED /* [CP] Check Pods Manifest.lock */,
112 | 7580E3FB25CB49A800F9A0A7 /* Sources */,
113 | 7580E3FC25CB49A800F9A0A7 /* Frameworks */,
114 | 7580E3FD25CB49A800F9A0A7 /* Resources */,
115 | 9DA9BB08D94F4D7740920AEF /* [CP] Embed Pods Frameworks */,
116 | );
117 | buildRules = (
118 | );
119 | dependencies = (
120 | );
121 | name = RxModalExample;
122 | packageProductDependencies = (
123 | 75D9706225D5438900EECC2B /* Splash */,
124 | );
125 | productName = RxModalExample;
126 | productReference = 7580E3FF25CB49A800F9A0A7 /* RxModalExample.app */;
127 | productType = "com.apple.product-type.application";
128 | };
129 | /* End PBXNativeTarget section */
130 |
131 | /* Begin PBXProject section */
132 | 7580E3F725CB49A800F9A0A7 /* Project object */ = {
133 | isa = PBXProject;
134 | attributes = {
135 | LastSwiftUpdateCheck = 1230;
136 | LastUpgradeCheck = 1230;
137 | TargetAttributes = {
138 | 7580E3FE25CB49A800F9A0A7 = {
139 | CreatedOnToolsVersion = 12.3;
140 | };
141 | };
142 | };
143 | buildConfigurationList = 7580E3FA25CB49A800F9A0A7 /* Build configuration list for PBXProject "RxModalExample" */;
144 | compatibilityVersion = "Xcode 9.3";
145 | developmentRegion = en;
146 | hasScannedForEncodings = 0;
147 | knownRegions = (
148 | en,
149 | Base,
150 | );
151 | mainGroup = 7580E3F625CB49A800F9A0A7;
152 | packageReferences = (
153 | 75D9706125D5438900EECC2B /* XCRemoteSwiftPackageReference "Splash" */,
154 | );
155 | productRefGroup = 7580E40025CB49A800F9A0A7 /* Products */;
156 | projectDirPath = "";
157 | projectRoot = "";
158 | targets = (
159 | 7580E3FE25CB49A800F9A0A7 /* RxModalExample */,
160 | );
161 | };
162 | /* End PBXProject section */
163 |
164 | /* Begin PBXResourcesBuildPhase section */
165 | 7580E3FD25CB49A800F9A0A7 /* Resources */ = {
166 | isa = PBXResourcesBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | 7580E40F25CB49A900F9A0A7 /* LaunchScreen.storyboard in Resources */,
170 | 7580E40C25CB49A900F9A0A7 /* Assets.xcassets in Resources */,
171 | 7580E40A25CB49A800F9A0A7 /* Main.storyboard in Resources */,
172 | );
173 | runOnlyForDeploymentPostprocessing = 0;
174 | };
175 | /* End PBXResourcesBuildPhase section */
176 |
177 | /* Begin PBXShellScriptBuildPhase section */
178 | 3E3353F6ABD85963532BD1ED /* [CP] Check Pods Manifest.lock */ = {
179 | isa = PBXShellScriptBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | );
183 | inputFileListPaths = (
184 | );
185 | inputPaths = (
186 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
187 | "${PODS_ROOT}/Manifest.lock",
188 | );
189 | name = "[CP] Check Pods Manifest.lock";
190 | outputFileListPaths = (
191 | );
192 | outputPaths = (
193 | "$(DERIVED_FILE_DIR)/Pods-RxModalExample-checkManifestLockResult.txt",
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | shellPath = /bin/sh;
197 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
198 | showEnvVarsInLog = 0;
199 | };
200 | 9DA9BB08D94F4D7740920AEF /* [CP] Embed Pods Frameworks */ = {
201 | isa = PBXShellScriptBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | );
205 | inputFileListPaths = (
206 | "${PODS_ROOT}/Target Support Files/Pods-RxModalExample/Pods-RxModalExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
207 | );
208 | name = "[CP] Embed Pods Frameworks";
209 | outputFileListPaths = (
210 | "${PODS_ROOT}/Target Support Files/Pods-RxModalExample/Pods-RxModalExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
211 | );
212 | runOnlyForDeploymentPostprocessing = 0;
213 | shellPath = /bin/sh;
214 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RxModalExample/Pods-RxModalExample-frameworks.sh\"\n";
215 | showEnvVarsInLog = 0;
216 | };
217 | /* End PBXShellScriptBuildPhase section */
218 |
219 | /* Begin PBXSourcesBuildPhase section */
220 | 7580E3FB25CB49A800F9A0A7 /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | 7580E40725CB49A800F9A0A7 /* FlowsListViewController.swift in Sources */,
225 | 75D9706925D571C600EECC2B /* Flow.swift in Sources */,
226 | 7580E40325CB49A800F9A0A7 /* AppDelegate.swift in Sources */,
227 | 7580E40525CB49A800F9A0A7 /* SceneDelegate.swift in Sources */,
228 | 75D9706625D5716000EECC2B /* FlowDetailViewController.swift in Sources */,
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | /* End PBXSourcesBuildPhase section */
233 |
234 | /* Begin PBXVariantGroup section */
235 | 7580E40825CB49A800F9A0A7 /* Main.storyboard */ = {
236 | isa = PBXVariantGroup;
237 | children = (
238 | 7580E40925CB49A800F9A0A7 /* Base */,
239 | );
240 | name = Main.storyboard;
241 | sourceTree = "";
242 | };
243 | 7580E40D25CB49A900F9A0A7 /* LaunchScreen.storyboard */ = {
244 | isa = PBXVariantGroup;
245 | children = (
246 | 7580E40E25CB49A900F9A0A7 /* Base */,
247 | );
248 | name = LaunchScreen.storyboard;
249 | sourceTree = "";
250 | };
251 | /* End PBXVariantGroup section */
252 |
253 | /* Begin XCBuildConfiguration section */
254 | 7580E41125CB49A900F9A0A7 /* Debug */ = {
255 | isa = XCBuildConfiguration;
256 | buildSettings = {
257 | ALWAYS_SEARCH_USER_PATHS = NO;
258 | CLANG_ANALYZER_NONNULL = YES;
259 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
261 | CLANG_CXX_LIBRARY = "libc++";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_ENABLE_OBJC_WEAK = YES;
265 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
266 | CLANG_WARN_BOOL_CONVERSION = YES;
267 | CLANG_WARN_COMMA = YES;
268 | CLANG_WARN_CONSTANT_CONVERSION = YES;
269 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
271 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
272 | CLANG_WARN_EMPTY_BODY = YES;
273 | CLANG_WARN_ENUM_CONVERSION = YES;
274 | CLANG_WARN_INFINITE_RECURSION = YES;
275 | CLANG_WARN_INT_CONVERSION = YES;
276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
280 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
281 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
282 | CLANG_WARN_STRICT_PROTOTYPES = YES;
283 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
284 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
285 | CLANG_WARN_UNREACHABLE_CODE = YES;
286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
287 | COPY_PHASE_STRIP = NO;
288 | DEBUG_INFORMATION_FORMAT = dwarf;
289 | ENABLE_STRICT_OBJC_MSGSEND = YES;
290 | ENABLE_TESTABILITY = YES;
291 | GCC_C_LANGUAGE_STANDARD = gnu11;
292 | GCC_DYNAMIC_NO_PIC = NO;
293 | GCC_NO_COMMON_BLOCKS = YES;
294 | GCC_OPTIMIZATION_LEVEL = 0;
295 | GCC_PREPROCESSOR_DEFINITIONS = (
296 | "DEBUG=1",
297 | "$(inherited)",
298 | );
299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
301 | GCC_WARN_UNDECLARED_SELECTOR = YES;
302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
303 | GCC_WARN_UNUSED_FUNCTION = YES;
304 | GCC_WARN_UNUSED_VARIABLE = YES;
305 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
306 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
307 | MTL_FAST_MATH = YES;
308 | ONLY_ACTIVE_ARCH = YES;
309 | SDKROOT = iphoneos;
310 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
311 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
312 | };
313 | name = Debug;
314 | };
315 | 7580E41225CB49A900F9A0A7 /* Release */ = {
316 | isa = XCBuildConfiguration;
317 | buildSettings = {
318 | ALWAYS_SEARCH_USER_PATHS = NO;
319 | CLANG_ANALYZER_NONNULL = YES;
320 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
321 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
322 | CLANG_CXX_LIBRARY = "libc++";
323 | CLANG_ENABLE_MODULES = YES;
324 | CLANG_ENABLE_OBJC_ARC = YES;
325 | CLANG_ENABLE_OBJC_WEAK = YES;
326 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
327 | CLANG_WARN_BOOL_CONVERSION = YES;
328 | CLANG_WARN_COMMA = YES;
329 | CLANG_WARN_CONSTANT_CONVERSION = YES;
330 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
331 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
332 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
333 | CLANG_WARN_EMPTY_BODY = YES;
334 | CLANG_WARN_ENUM_CONVERSION = YES;
335 | CLANG_WARN_INFINITE_RECURSION = YES;
336 | CLANG_WARN_INT_CONVERSION = YES;
337 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
338 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
339 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
340 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
341 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
342 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
343 | CLANG_WARN_STRICT_PROTOTYPES = YES;
344 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
345 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
346 | CLANG_WARN_UNREACHABLE_CODE = YES;
347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
348 | COPY_PHASE_STRIP = NO;
349 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
350 | ENABLE_NS_ASSERTIONS = NO;
351 | ENABLE_STRICT_OBJC_MSGSEND = YES;
352 | GCC_C_LANGUAGE_STANDARD = gnu11;
353 | GCC_NO_COMMON_BLOCKS = YES;
354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
356 | GCC_WARN_UNDECLARED_SELECTOR = YES;
357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
358 | GCC_WARN_UNUSED_FUNCTION = YES;
359 | GCC_WARN_UNUSED_VARIABLE = YES;
360 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
361 | MTL_ENABLE_DEBUG_INFO = NO;
362 | MTL_FAST_MATH = YES;
363 | SDKROOT = iphoneos;
364 | SWIFT_COMPILATION_MODE = wholemodule;
365 | SWIFT_OPTIMIZATION_LEVEL = "-O";
366 | VALIDATE_PRODUCT = YES;
367 | };
368 | name = Release;
369 | };
370 | 7580E41425CB49A900F9A0A7 /* Debug */ = {
371 | isa = XCBuildConfiguration;
372 | baseConfigurationReference = A8FF776624B518F974CE128B /* Pods-RxModalExample.debug.xcconfig */;
373 | buildSettings = {
374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
375 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
376 | CODE_SIGN_ENTITLEMENTS = RxModalExample/RxModalExample.entitlements;
377 | CODE_SIGN_IDENTITY = "Apple Development";
378 | CODE_SIGN_STYLE = Automatic;
379 | DEVELOPMENT_TEAM = JKFCB4CN7C;
380 | INFOPLIST_FILE = RxModalExample/Info.plist;
381 | LD_RUNPATH_SEARCH_PATHS = (
382 | "$(inherited)",
383 | "@executable_path/Frameworks",
384 | );
385 | PRODUCT_BUNDLE_IDENTIFIER = com.RxSwiftCommunity.RxModalExample;
386 | PRODUCT_NAME = "$(TARGET_NAME)";
387 | PROVISIONING_PROFILE_SPECIFIER = "";
388 | SUPPORTS_MACCATALYST = YES;
389 | SWIFT_VERSION = 5.0;
390 | TARGETED_DEVICE_FAMILY = "1,2";
391 | };
392 | name = Debug;
393 | };
394 | 7580E41525CB49A900F9A0A7 /* Release */ = {
395 | isa = XCBuildConfiguration;
396 | baseConfigurationReference = 225B62DC46C283E24EADD0CE /* Pods-RxModalExample.release.xcconfig */;
397 | buildSettings = {
398 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
399 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
400 | CODE_SIGN_ENTITLEMENTS = RxModalExample/RxModalExample.entitlements;
401 | CODE_SIGN_IDENTITY = "Apple Development";
402 | CODE_SIGN_STYLE = Automatic;
403 | DEVELOPMENT_TEAM = JKFCB4CN7C;
404 | INFOPLIST_FILE = RxModalExample/Info.plist;
405 | LD_RUNPATH_SEARCH_PATHS = (
406 | "$(inherited)",
407 | "@executable_path/Frameworks",
408 | );
409 | PRODUCT_BUNDLE_IDENTIFIER = com.RxSwiftCommunity.RxModalExample;
410 | PRODUCT_NAME = "$(TARGET_NAME)";
411 | PROVISIONING_PROFILE_SPECIFIER = "";
412 | SUPPORTS_MACCATALYST = YES;
413 | SWIFT_VERSION = 5.0;
414 | TARGETED_DEVICE_FAMILY = "1,2";
415 | };
416 | name = Release;
417 | };
418 | /* End XCBuildConfiguration section */
419 |
420 | /* Begin XCConfigurationList section */
421 | 7580E3FA25CB49A800F9A0A7 /* Build configuration list for PBXProject "RxModalExample" */ = {
422 | isa = XCConfigurationList;
423 | buildConfigurations = (
424 | 7580E41125CB49A900F9A0A7 /* Debug */,
425 | 7580E41225CB49A900F9A0A7 /* Release */,
426 | );
427 | defaultConfigurationIsVisible = 0;
428 | defaultConfigurationName = Release;
429 | };
430 | 7580E41325CB49A900F9A0A7 /* Build configuration list for PBXNativeTarget "RxModalExample" */ = {
431 | isa = XCConfigurationList;
432 | buildConfigurations = (
433 | 7580E41425CB49A900F9A0A7 /* Debug */,
434 | 7580E41525CB49A900F9A0A7 /* Release */,
435 | );
436 | defaultConfigurationIsVisible = 0;
437 | defaultConfigurationName = Release;
438 | };
439 | /* End XCConfigurationList section */
440 |
441 | /* Begin XCRemoteSwiftPackageReference section */
442 | 75D9706125D5438900EECC2B /* XCRemoteSwiftPackageReference "Splash" */ = {
443 | isa = XCRemoteSwiftPackageReference;
444 | repositoryURL = "https://github.com/JohnSundell/Splash";
445 | requirement = {
446 | kind = upToNextMajorVersion;
447 | minimumVersion = 0.15.0;
448 | };
449 | };
450 | /* End XCRemoteSwiftPackageReference section */
451 |
452 | /* Begin XCSwiftPackageProductDependency section */
453 | 75D9706225D5438900EECC2B /* Splash */ = {
454 | isa = XCSwiftPackageProductDependency;
455 | package = 75D9706125D5438900EECC2B /* XCRemoteSwiftPackageReference "Splash" */;
456 | productName = Splash;
457 | };
458 | /* End XCSwiftPackageProductDependency section */
459 | };
460 | rootObject = 7580E3F725CB49A800F9A0A7 /* Project object */;
461 | }
462 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
21 |
22 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Splash",
6 | "repositoryURL": "https://github.com/JohnSundell/Splash",
7 | "state": {
8 | "branch": null,
9 | "revision": "81de0389558ad40579027735841593b21a511fa8",
10 | "version": "0.15.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // RxModalExample
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "icon_60pt@2x.png",
35 | "idiom" : "iphone",
36 | "scale" : "2x",
37 | "size" : "60x60"
38 | },
39 | {
40 | "filename" : "icon_60pt@3x.png",
41 | "idiom" : "iphone",
42 | "scale" : "3x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "idiom" : "ipad",
47 | "scale" : "1x",
48 | "size" : "20x20"
49 | },
50 | {
51 | "idiom" : "ipad",
52 | "scale" : "2x",
53 | "size" : "20x20"
54 | },
55 | {
56 | "idiom" : "ipad",
57 | "scale" : "1x",
58 | "size" : "29x29"
59 | },
60 | {
61 | "idiom" : "ipad",
62 | "scale" : "2x",
63 | "size" : "29x29"
64 | },
65 | {
66 | "idiom" : "ipad",
67 | "scale" : "1x",
68 | "size" : "40x40"
69 | },
70 | {
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "40x40"
74 | },
75 | {
76 | "filename" : "icon_76pt.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "76x76"
80 | },
81 | {
82 | "filename" : "icon_76pt@2x.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "76x76"
86 | },
87 | {
88 | "filename" : "icon_83.5@2x.png",
89 | "idiom" : "ipad",
90 | "scale" : "2x",
91 | "size" : "83.5x83.5"
92 | },
93 | {
94 | "filename" : "Icon.png",
95 | "idiom" : "ios-marketing",
96 | "scale" : "1x",
97 | "size" : "1024x1024"
98 | },
99 | {
100 | "idiom" : "mac",
101 | "scale" : "1x",
102 | "size" : "16x16"
103 | },
104 | {
105 | "idiom" : "mac",
106 | "scale" : "2x",
107 | "size" : "16x16"
108 | },
109 | {
110 | "idiom" : "mac",
111 | "scale" : "1x",
112 | "size" : "32x32"
113 | },
114 | {
115 | "idiom" : "mac",
116 | "scale" : "2x",
117 | "size" : "32x32"
118 | },
119 | {
120 | "filename" : "icon_128pt.png",
121 | "idiom" : "mac",
122 | "scale" : "1x",
123 | "size" : "128x128"
124 | },
125 | {
126 | "filename" : "icon_256pt-1.png",
127 | "idiom" : "mac",
128 | "scale" : "2x",
129 | "size" : "128x128"
130 | },
131 | {
132 | "filename" : "icon_256pt.png",
133 | "idiom" : "mac",
134 | "scale" : "1x",
135 | "size" : "256x256"
136 | },
137 | {
138 | "filename" : "icon_512pt-1.png",
139 | "idiom" : "mac",
140 | "scale" : "2x",
141 | "size" : "256x256"
142 | },
143 | {
144 | "filename" : "icon_512pt.png",
145 | "idiom" : "mac",
146 | "scale" : "1x",
147 | "size" : "512x512"
148 | },
149 | {
150 | "filename" : "icon_512pt@2x.png",
151 | "idiom" : "mac",
152 | "scale" : "2x",
153 | "size" : "512x512"
154 | }
155 | ],
156 | "info" : {
157 | "author" : "xcode",
158 | "version" : 1
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_128pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_128pt.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_256pt-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_256pt-1.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_256pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_256pt.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt-1.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_512pt@2x.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_76pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_76pt.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/RxModalExample/RxModalExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/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 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/Flow.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Flow.swift
3 | // RxModalExample
4 | //
5 | // Created by Jérôme Alves on 11/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxSwift
10 | import RxModal
11 |
12 | struct Flow {
13 | let title: String
14 | let source: (UIBarButtonItem) -> Observable
15 |
16 | init(_ title: String, source: @escaping () -> O) {
17 | self = .init(title, source: { _ in source() })
18 | }
19 |
20 | init(_ title: String, source: @escaping (UIBarButtonItem) -> O) {
21 | self.title = title
22 | self.source = { sender in
23 | source(sender)
24 | .asObservable()
25 | .map { String(rxModalDescribing: $0) }
26 | .materialize()
27 | .map { ".\($0)" }
28 | .startWith(
29 | "\(O.self)"
30 | .replacingOccurrences(of: "PrimitiveSequence<", with: "")
31 | .replacingOccurrences(of: "Trait, ", with: "<"),
32 | ".subscribe"
33 | )
34 | .concat(Single.just(".dispose"))
35 | }
36 | }
37 |
38 | static var allFlows: [Flow] = {
39 | var flows = [
40 | Flow("Alert") {
41 | RxModal.alert(
42 | AlertResult.self,
43 | title: "Delete Item",
44 | message: "Are you sure you want to delete something?",
45 | actions: [
46 | .cancel(title: "Cancel", mapTo: .cancel),
47 | .destructive(title: "Delete", mapTo: .delete)
48 | ]
49 | )
50 | },
51 | Flow("Action Sheet") { sender in
52 | RxModal.actionSheet(
53 | AlertResult.self,
54 | source: .barButtonItem(sender),
55 | title: "Delete Item",
56 | message: "Are you sure you want to delete something?",
57 | actions: [
58 | .cancel(title: "Cancel", mapTo: .cancel),
59 | .destructive(title: "Delete", mapTo: .delete)
60 | ]
61 | )
62 | },
63 | Flow("Media Picker") {
64 | RxModal.mediaPicker {
65 | $0.allowsPickingMultipleItems = true
66 | }.map(\.items)
67 | },
68 | Flow("Mail Composer") {
69 | RxModal.mailComposer {
70 | $0.setToRecipients(["rxmodal@rxswiftcommunity.org"])
71 | $0.setSubject("RxModal")
72 | $0.setMessageBody("""
73 | Hey,
74 | This library is awesome!
75 | Thanks :)
76 | """, isHTML: false)
77 | }
78 | },
79 | Flow("Message Composer") {
80 | RxModal.messageComposer {
81 | $0.recipients = ["0639981337"]
82 | $0.body = """
83 | Hey,
84 | This library is awesome!
85 | Thanks :)
86 | """
87 | }
88 | },
89 | Flow("Composer Chooser") { sender in
90 | RxModal.actionSheet(
91 | source: .barButtonItem(sender),
92 | title: "Contact Us",
93 | actions: [
94 | .default(title: "Mail", flatMapTo: RxModal.mailComposer {
95 | $0.setToRecipients(["rxmodal@rxswiftcommunity.org"])
96 | $0.setMessageBody("Hello World!", isHTML: false)
97 | }),
98 | .default(title: "Message", flatMapTo: RxModal.messageComposer {
99 | $0.recipients = ["0639981337"]
100 | $0.body = "Hello World!"
101 | }),
102 | .cancel(title: "Cancel")
103 | ]
104 | )
105 | },
106 | Flow("Sign In alert") {
107 | RxModal.alert(
108 | title: "Sign in",
109 | message: "Please sign in using your credentials",
110 | textFields: [
111 | DialogTextField.email { $0.placeholder = "e-mail" },
112 | DialogTextField.password { $0.placeholder = "password" }
113 | ],
114 | actions: [
115 | .cancel(title: "Cancel"),
116 | .default(title: "Sign In") { textFields in
117 | Credentials(
118 | email: textFields[0].text ?? "",
119 | password: textFields[1].text ?? ""
120 | )
121 | },
122 | ]
123 | )
124 | }
125 | ]
126 |
127 | #if targetEnvironment(macCatalyst)
128 | // OAuth playgrounds seem to work only on macOS 🤷🏻♂️
129 | flows.append(
130 | Flow("Web Session") { () -> Single in
131 | RxModal.alert(
132 | String?.self,
133 | title: "Client ID",
134 | message: "You must register a playground client on oauth.com first",
135 | textFields: [DialogTextField { $0.placeholder = "CLIENT ID" }],
136 | actions: [
137 | .cancel(title: "Cancel", throw: WebSessionError.missingClientID),
138 | .default(title: "Register New Client", mapTo: nil),
139 | .preferred(.default(title: "Continue", map: { $0.first?.text })),
140 | ])
141 | .asSingle()
142 | .flatMap { clientID in
143 | guard let clientID = clientID else {
144 | UIApplication.shared.open(URL(string: "https://www.oauth.com/playground/client-registration.html")!)
145 | throw WebSessionError.missingClientID
146 | }
147 | return RxModal.webAuthenticationSession(
148 | url: URL(string: "https://www.oauth.com/playground/auth-dialog.html?response_type=token&client_id=\(clientID)&redirect_uri=rx-modal-example://&scope=photo&state=NESR37xhi7JGQ6xI")!,
149 | callbackURLScheme: "rx-modal-example"
150 | )
151 | }
152 | }
153 | )
154 | #endif
155 |
156 | if #available(iOS 14, *) {
157 | flows.append(
158 | Flow("Photo Picker") {
159 | RxModal.photoPicker {
160 | $0.selectionLimit = 3
161 | }
162 | }
163 | )
164 | }
165 |
166 | return flows
167 | }()
168 |
169 | }
170 |
171 | enum AlertResult {
172 | case delete, cancel
173 | }
174 |
175 | enum WebSessionError: Error {
176 | case missingClientID
177 | }
178 |
179 | struct Credentials {
180 | let email: String
181 | let password: String
182 | }
183 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/FlowDetailViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FlowDetailViewController.swift
3 | // RxModalExample
4 | //
5 | // Created by Jérôme Alves on 11/02/2021.
6 | //
7 |
8 | import UIKit
9 | import Splash
10 | import RxSwift
11 |
12 | final class FlowDetailViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | navigationItem.title = flow?.title
17 | navigationItem.rightBarButtonItem = startBarButtonItem
18 | flowOutputTextView.backgroundColor = format.theme.backgroundColor
19 | flowOutputTextView.textColor = .white
20 | flowOutputTextView.font = UIFont.monospacedSystemFont(ofSize: 17, weight: .regular)
21 | }
22 |
23 | deinit {
24 | flowDisposable?.dispose()
25 | }
26 |
27 | // MARK: - Output Text View
28 |
29 | @IBOutlet weak var flowOutputTextView: UITextView!
30 |
31 | private let format = AttributedStringOutputFormat(theme: .sundellsColors(withFont: Font(size: 17)))
32 | private lazy var highlighter = SyntaxHighlighter(format: format)
33 |
34 | // MARK: - Flow Lifecycle
35 |
36 | var flow: Flow?
37 |
38 | @IBOutlet weak var startBarButtonItem: UIBarButtonItem!
39 |
40 | @IBAction func startFlow(_ sender: Any) {
41 | flowDisposable = flow?
42 | .source(startBarButtonItem)
43 | .scan("") { (result, event) -> String in
44 | [result, event]
45 | .filter { $0.isEmpty == false }
46 | .joined(separator: "\n\n")
47 | }
48 | .map(highlighter.highlight)
49 | .bind(to: flowOutputTextView.rx.attributedText)
50 | }
51 |
52 | private var flowDisposable: Disposable? {
53 | didSet { oldValue?.dispose() }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/FlowsListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // RxModalExample
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxModal
10 | import RxSwift
11 | import PhotosUI
12 | import RxCocoa
13 |
14 | class FlowsListViewController: UITableViewController {
15 |
16 | // MARK: - Lifecycle
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | }
21 |
22 | override func viewWillAppear(_ animated: Bool) {
23 | super.viewWillAppear(animated)
24 | transitionCoordinator?.animate(alongsideTransition: { _ in
25 | for indexPath in self.tableView.indexPathsForSelectedRows ?? [] {
26 | self.tableView.deselectRow(at: indexPath, animated: true)
27 | }
28 | }, completion: nil)
29 | }
30 |
31 | // MARK: - Table View
32 |
33 | override func numberOfSections(in tableView: UITableView) -> Int {
34 | 1
35 | }
36 |
37 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
38 | Flow.allFlows.count
39 | }
40 |
41 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
42 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! FlowCell
43 | cell.flow = Flow.allFlows[indexPath.row]
44 | return cell
45 | }
46 |
47 | // MARK: - Segues
48 |
49 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
50 | super.prepare(for: segue, sender: sender)
51 |
52 | guard
53 | let navigationController = segue.destination as? UINavigationController,
54 | let flowDetail = navigationController.topViewController as? FlowDetailViewController,
55 | let cell = sender as? FlowCell else {
56 | return
57 | }
58 |
59 | flowDetail.flow = cell.flow
60 | }
61 | }
62 |
63 | final class FlowCell: UITableViewCell {
64 | var flow: Flow? {
65 | didSet {
66 | textLabel?.text = flow?.title
67 | accessoryType = .disclosureIndicator
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/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 | RxModal
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleURLTypes
20 |
21 |
22 | CFBundleTypeRole
23 | Viewer
24 | CFBundleURLName
25 | app
26 | CFBundleURLSchemes
27 |
28 | rx-modal-example
29 |
30 |
31 |
32 | CFBundleVersion
33 | 1
34 | LSRequiresIPhoneOS
35 |
36 | NSAppleMusicUsageDescription
37 | RxModal Demo
38 | UIApplicationSceneManifest
39 |
40 | UIApplicationSupportsMultipleScenes
41 |
42 | UISceneConfigurations
43 |
44 | UIWindowSceneSessionRoleApplication
45 |
46 |
47 | UISceneConfigurationName
48 | Default Configuration
49 | UISceneDelegateClassName
50 | $(PRODUCT_MODULE_NAME).SceneDelegate
51 | UISceneStoryboardFile
52 | Main
53 |
54 |
55 |
56 |
57 | UIApplicationSupportsIndirectInputEvents
58 |
59 | UILaunchStoryboardName
60 | LaunchScreen
61 | UIMainStoryboardFile
62 | Main
63 | UIRequiredDeviceCapabilities
64 |
65 | armv7
66 |
67 | UISupportedInterfaceOrientations
68 |
69 | UIInterfaceOrientationPortrait
70 | UIInterfaceOrientationLandscapeLeft
71 | UIInterfaceOrientationLandscapeRight
72 |
73 | UISupportedInterfaceOrientations~ipad
74 |
75 | UIInterfaceOrientationPortrait
76 | UIInterfaceOrientationPortraitUpsideDown
77 | UIInterfaceOrientationLandscapeLeft
78 | UIInterfaceOrientationLandscapeRight
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/RxModalExample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/RxModalExample/RxModalExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // RxModalExample
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/Sources/Composers/MFMailComposeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MFMailComposeViewController.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 06/02/2021.
6 | //
7 |
8 | #if canImport(MessageUI)
9 | import UIKit
10 | import MessageUI
11 | import RxSwift
12 |
13 | extension RxModal {
14 |
15 | public static func mailComposer(presenter: Presenter = .keyWindow, configuration: @escaping (MFMailComposeViewController) -> Void = { _ in }) -> Single {
16 | .deferred {
17 | guard MFMailComposeViewController.canSendMail() else {
18 | throw RxModalError.unsupported
19 | }
20 | return MFMailComposeViewControllerCoordinator.present(using: presenter) { delegate in
21 | MFMailComposeViewController()..{
22 | configuration($0)
23 | $0.mailComposeDelegate = delegate
24 | }
25 | } sequence: {
26 | $0.composerResult.asSingle()
27 | }
28 | }
29 | }
30 | }
31 |
32 | private class MFMailComposeViewControllerCoordinator: RxModalCoordinator, MFMailComposeViewControllerDelegate {
33 | required init() {}
34 |
35 | let composerResult = PublishSubject()
36 |
37 | func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
38 | if let error = error {
39 | composerResult.onError(error)
40 | } else {
41 | composerResult.onNext(result)
42 | composerResult.onCompleted()
43 | }
44 | }
45 | }
46 | #endif
47 |
--------------------------------------------------------------------------------
/Sources/Composers/MFMessageComposeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MFMailComposeViewController.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 06/02/2021.
6 | //
7 |
8 | #if canImport(MessageUI)
9 | import UIKit
10 | import MessageUI
11 | import RxSwift
12 |
13 | extension RxModal {
14 |
15 | public static func messageComposer(presenter: Presenter = .keyWindow, configuration: @escaping (MFMessageComposeViewController) -> Void = { _ in }) -> Single {
16 | .deferred {
17 | guard MFMessageComposeViewController.canSendText() else {
18 | throw RxModalError.unsupported
19 | }
20 | return MFMessageComposeViewControllerCoordinator.present(using: presenter) { delegate in
21 | MFMessageComposeViewController()..{
22 | configuration($0)
23 | $0.messageComposeDelegate = delegate
24 | }
25 | } sequence: {
26 | $0.composerResult.asSingle()
27 | }
28 | }
29 | }
30 | }
31 |
32 | private class MFMessageComposeViewControllerCoordinator: RxModalCoordinator, MFMessageComposeViewControllerDelegate {
33 | required init() {}
34 |
35 | let composerResult = PublishSubject()
36 |
37 | func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
38 | composerResult.onNext(result)
39 | composerResult.onCompleted()
40 | }
41 | }
42 | #endif
43 |
--------------------------------------------------------------------------------
/Sources/Dialogs/Dialog.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dialog.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 07/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxSwift
10 |
11 | public struct Dialog {
12 | public let title: String?
13 | public let message: String?
14 | public let textFields: [DialogTextField]
15 | public let actions: [DialogAction]
16 |
17 | public init(title: String? = nil, message: String? = nil, textFields: [DialogTextField] = [], actions: [DialogAction]) {
18 | assert(actions.isEmpty == false, "Must have at least one action")
19 |
20 | self.title = title
21 | self.message = message
22 | self.textFields = textFields
23 | self.actions = actions
24 | }
25 | }
26 |
27 | public enum DialogActionStyle {
28 | case `default`
29 | case cancel
30 | case destructive
31 | }
32 |
33 | public struct DialogTextField {
34 | internal let configuration: (UITextField) -> ()
35 | public init(configuration: @escaping (UITextField) -> () = { _ in }) {
36 | self.configuration = configuration
37 | }
38 |
39 | public static func email(configuration: @escaping (UITextField) -> () = { _ in }) -> DialogTextField {
40 | DialogTextField {
41 | if #available(iOS 10.0, *) {
42 | $0.textContentType = .emailAddress
43 | }
44 | $0.keyboardType = .emailAddress
45 | $0.autocapitalizationType = .none
46 | $0.spellCheckingType = .no
47 | configuration($0)
48 | }
49 | }
50 |
51 | public static func password(configuration: @escaping (UITextField) -> () = { _ in }) -> DialogTextField {
52 | DialogTextField {
53 | if #available(iOS 11.0, *) {
54 | $0.textContentType = .password
55 | }
56 | $0.isSecureTextEntry = true
57 | $0.autocapitalizationType = .none
58 | $0.autocorrectionType = .no
59 | $0.spellCheckingType = .no
60 | configuration($0)
61 | }
62 | }
63 |
64 | public static func phoneNumber(configuration: @escaping (UITextField) -> () = { _ in }) -> DialogTextField {
65 | DialogTextField {
66 | if #available(iOS 11.0, *) {
67 | $0.textContentType = .telephoneNumber
68 | }
69 | $0.keyboardType = .phonePad
70 | $0.autocapitalizationType = .none
71 | $0.autocorrectionType = .no
72 | $0.spellCheckingType = .no
73 | configuration($0)
74 | }
75 | }
76 | }
77 |
78 | public struct DialogAction {
79 | public let title: String
80 | public let style: DialogActionStyle
81 | public let onNext: ([UITextField]) -> Observable
82 | public let isPreferred: Bool
83 |
84 | public init(title: String, style: DialogActionStyle, onNext: @escaping ([UITextField]) -> Observable, isPreferred: Bool = false) {
85 | self.title = title
86 | self.style = style
87 | self.onNext = onNext
88 | self.isPreferred = isPreferred
89 | }
90 |
91 | public func withStyle(_ newStyle: DialogActionStyle) -> DialogAction {
92 | DialogAction(
93 | title: title,
94 | style: newStyle,
95 | onNext: onNext,
96 | isPreferred: isPreferred
97 | )
98 | }
99 |
100 | // MARK: - flatMap with TextFields
101 |
102 | public static func `default`(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction where O.Element == T {
103 | DialogAction(title: title, style: .default, onNext: { observable($0).asObservable() })
104 | }
105 |
106 | public static func cancel(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction where O.Element == T {
107 | DialogAction(title: title, style: .cancel, onNext: { observable($0).asObservable() })
108 | }
109 |
110 | public static func destructive(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction where O.Element == T {
111 | DialogAction(title: title, style: .destructive, onNext: { observable($0).asObservable() })
112 | }
113 |
114 | // MARK: - flatMapTo without TextFields
115 |
116 | public static func `default`(title: String, flatMapTo observable: O) -> DialogAction where O.Element == T {
117 | DialogAction(title: title, style: .default, onNext: { _ in observable.asObservable() })
118 | }
119 |
120 | public static func cancel(title: String, flatMapTo observable: O) -> DialogAction where O.Element == T {
121 | DialogAction(title: title, style: .cancel, onNext: { _ in observable.asObservable() })
122 | }
123 |
124 | public static func destructive(title: String, flatMapTo observable: O) -> DialogAction where O.Element == T {
125 | DialogAction(title: title, style: .destructive, onNext: { _ in observable.asObservable() })
126 | }
127 |
128 | // MARK: - map with TextFields
129 |
130 | public static func `default`(title: String, map value: @escaping ([UITextField]) -> T) -> DialogAction {
131 | .default(title: title, flatMap: { Observable.just(value($0)) })
132 | }
133 |
134 | public static func cancel(title: String, map value: @escaping ([UITextField]) -> T) -> DialogAction {
135 | .cancel(title: title, flatMap: { Observable.just(value($0)) })
136 | }
137 |
138 | public static func destructive(title: String, map value: @escaping ([UITextField]) -> T) -> DialogAction {
139 | .destructive(title: title, flatMap: { Observable.just(value($0)) })
140 | }
141 |
142 | // MARK: - mapTo without TextFields
143 |
144 | public static func `default`(title: String, mapTo value: T) -> DialogAction {
145 | .default(title: title, flatMapTo: Observable.just(value))
146 | }
147 |
148 | public static func cancel(title: String, mapTo value: T) -> DialogAction {
149 | .cancel(title: title, flatMapTo: Observable.just(value))
150 | }
151 |
152 | public static func destructive(title: String, mapTo value: T) -> DialogAction {
153 | .destructive(title: title, flatMapTo: Observable.just(value))
154 | }
155 |
156 | // MARK: - Throw
157 |
158 | public static func `default`(title: String, throw error: Error) -> DialogAction {
159 | .default(title: title, flatMapTo: Observable.error(error))
160 | }
161 |
162 | public static func cancel(title: String, throw error: Error) -> DialogAction {
163 | .cancel(title: title, flatMapTo: Observable.error(error))
164 | }
165 |
166 | public static func destructive(title: String, throw error: Error) -> DialogAction {
167 | .destructive(title: title, flatMapTo: Observable.error(error))
168 | }
169 |
170 | // MARK: - No Values
171 |
172 | public static func `default`(title: String) -> DialogAction {
173 | .default(title: title, flatMapTo: Observable.empty())
174 | }
175 |
176 | public static func cancel(title: String) -> DialogAction {
177 | .cancel(title: title, flatMapTo: Observable.empty())
178 | }
179 |
180 | public static func destructive(title: String) -> DialogAction {
181 | .destructive(title: title, flatMapTo: Observable.empty())
182 | }
183 |
184 | // MARK: - Higher Order Actions
185 |
186 | public static func preferred(_ action: DialogAction) -> DialogAction {
187 | DialogAction(
188 | title: action.title,
189 | style: action.style,
190 | onNext: action.onNext,
191 | isPreferred: true
192 | )
193 | }
194 | }
195 |
196 | extension DialogAction where T == Void {
197 | // MARK: - flatMap with TextFields
198 |
199 | public static func `default`(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction {
200 | DialogAction(title: title, style: .default, onNext: { observable($0).asObservable().map { _ in () } })
201 | }
202 |
203 | public static func cancel(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction {
204 | DialogAction(title: title, style: .cancel, onNext: { observable($0).asObservable().map { _ in () } })
205 | }
206 |
207 | public static func destructive(title: String, flatMap observable: @escaping ([UITextField]) -> O) -> DialogAction {
208 | DialogAction(title: title, style: .destructive, onNext: { observable($0).asObservable().map { _ in () } })
209 | }
210 |
211 | // MARK: - flatMapTo without TextFields
212 |
213 | public static func `default`(title: String, flatMapTo observable: O) -> DialogAction {
214 | DialogAction(title: title, style: .default, onNext: { _ in observable.asObservable().map { _ in () } })
215 | }
216 |
217 | public static func cancel(title: String, flatMapTo observable: O) -> DialogAction {
218 | DialogAction(title: title, style: .cancel, onNext: { _ in observable.asObservable().map { _ in () } })
219 | }
220 |
221 | public static func destructive(title: String, flatMapTo observable: O) -> DialogAction {
222 | DialogAction(title: title, style: .destructive, onNext: { _ in observable.asObservable().map { _ in () } })
223 | }
224 |
225 | }
226 |
--------------------------------------------------------------------------------
/Sources/Dialogs/UIAlertController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIAlertController.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 07/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxSwift
10 |
11 | extension DialogActionStyle {
12 | fileprivate var alertActionStyle: UIAlertAction.Style {
13 | switch self {
14 | case .default:
15 | return .default
16 | case .cancel:
17 | return .cancel
18 | case .destructive:
19 | return .destructive
20 | }
21 | }
22 | }
23 |
24 | extension DialogAction {
25 | fileprivate func makeAlertAction(observer: AnyObserver>, textFields: @escaping () -> [UITextField]) -> UIAlertAction {
26 | UIAlertAction(title: title, style: style.alertActionStyle) { _ in
27 | observer.onNext(self.onNext(textFields()))
28 | observer.onCompleted()
29 | }
30 | }
31 | }
32 |
33 | extension Dialog {
34 | fileprivate func makeAlertController(style: DialogStyle, observer: AnyObserver>) -> UIAlertController {
35 | let controller: UIAlertController
36 |
37 | switch style {
38 | case .alert:
39 | controller = UIAlertController(title: title, message: message, preferredStyle: .alert)
40 | case .actionSheet(let source):
41 | controller = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
42 | switch source {
43 | case .view(let view, let rect):
44 | controller.popoverPresentationController?.sourceRect = rect
45 | controller.popoverPresentationController?.sourceView = view
46 | case .barButtonItem(let item):
47 | controller.popoverPresentationController?.barButtonItem = item
48 | }
49 | }
50 |
51 | if case .alert = style {
52 | for textField in textFields {
53 | controller.addTextField(configurationHandler: textField.configuration)
54 | }
55 | }
56 |
57 | for action in actions {
58 | let alertAction = action.makeAlertAction(observer: observer) { [unowned controller] in
59 | controller.textFields ?? []
60 | }
61 | controller.addAction(alertAction)
62 | if action.isPreferred {
63 | controller.preferredAction = alertAction
64 | }
65 | }
66 |
67 | return controller
68 | }
69 | }
70 |
71 | public enum DialogSource {
72 | case view(UIView, rect: CGRect)
73 | case barButtonItem(UIBarButtonItem)
74 | public static func bounds(_ view: UIView) -> DialogSource {
75 | .view(view, rect: view.bounds)
76 | }
77 | }
78 |
79 | public enum DialogStyle {
80 | case alert
81 | case actionSheet(source: DialogSource)
82 | }
83 |
84 | extension RxModal {
85 | public static func alert(
86 | _ type: T.Type = T.self,
87 | presenter: Presenter = .keyWindow,
88 | title: String? = nil,
89 | message: String? = nil,
90 | textFields: [DialogTextField] = [],
91 | actions: [DialogAction]
92 | ) -> Observable {
93 | present(.alert, presenter: presenter, title: title, message: message, textFields: textFields, actions: actions)
94 | }
95 |
96 | public static func actionSheet(
97 | _ type: T.Type = T.self,
98 | presenter: Presenter = .keyWindow,
99 | source: DialogSource,
100 | title: String? = nil,
101 | message: String? = nil,
102 | actions: [DialogAction]
103 | ) -> Observable {
104 | present(.actionSheet(source: source), presenter: presenter, title: title, message: message, actions: actions)
105 | }
106 |
107 | public static func present(
108 | _ style: DialogStyle,
109 | type: T.Type = T.self,
110 | presenter: Presenter = .keyWindow,
111 | title: String? = nil,
112 | message: String? = nil,
113 | textFields: [DialogTextField] = [],
114 | actions: [DialogAction]
115 | ) -> Observable {
116 | let dialog = Dialog(title: title, message: message, textFields: textFields, actions: actions)
117 | return present( dialog, style: style, presenter: presenter)
118 | }
119 |
120 | public static func present(
121 | _ dialog: Dialog,
122 | style: DialogStyle,
123 | presenter: Presenter = .keyWindow
124 | ) -> Observable {
125 | UIAlertControllerCoordinator.present(using: presenter) { coordinator in
126 | dialog.makeAlertController(style: style, observer: coordinator.result.asObserver())
127 | } sequence: { coordinator in
128 | coordinator.result.merge()
129 | }
130 | }
131 | }
132 |
133 | private class UIAlertControllerCoordinator: RxModalCoordinator {
134 | required init() {}
135 | let result = PublishSubject>()
136 | }
137 |
--------------------------------------------------------------------------------
/Sources/Internals.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Internals.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 05/02/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | infix operator ..: MultiplicationPrecedence
11 |
12 | @discardableResult
13 | internal func .. (object: T, configuration: (inout T) -> Void) -> T {
14 | var copy = object
15 | configuration(©)
16 | return copy
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/Other/ASWebAuthenticationSession.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ASWebAuthenticationSession.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 10/02/2021.
6 | //
7 |
8 | import UIKit
9 | import AuthenticationServices
10 | import RxSwift
11 |
12 | extension RxModal {
13 |
14 | @available(iOS 12.0, *)
15 | public static func webAuthenticationSession(
16 | presenter: Presenter = .keyWindow,
17 | url: URL,
18 | callbackURLScheme: String,
19 | configuration: @escaping (ASWebAuthenticationSession) -> Void = { _ in }
20 | ) -> Single {
21 | .using {
22 | try RxWebAuthenticationSessionCoordinator(
23 | presenter: presenter,
24 | url: url,
25 | callbackURLScheme: callbackURLScheme,
26 | configuration: configuration
27 | )
28 | } primitiveSequenceFactory: { coordinator in
29 | coordinator.result.asSingle()
30 | }
31 | }
32 | }
33 |
34 | @available(iOS 12.0, *)
35 | private class RxWebAuthenticationSessionCoordinator: NSObject, ASWebAuthenticationPresentationContextProviding, Disposable {
36 | var window: UIWindow!
37 | let session: ASWebAuthenticationSession
38 | let result: PublishSubject
39 |
40 | init(
41 | presenter: Presenter,
42 | url: URL,
43 | callbackURLScheme: String,
44 | configuration: @escaping (ASWebAuthenticationSession) -> Void
45 | ) throws {
46 | let result = PublishSubject()
47 | let session = ASWebAuthenticationSession(
48 | url: url,
49 | callbackURLScheme: callbackURLScheme,
50 | completionHandler: { url, error in
51 | if let error = error {
52 | return result.onError(error)
53 | }
54 | guard let url = url else {
55 | return result.onError(RxModalError.unsupported)
56 | }
57 | result.onNext(url)
58 | result.onCompleted()
59 | }
60 | )
61 |
62 | configuration(session)
63 |
64 | self.result = result
65 | self.session = session
66 |
67 | super.init()
68 |
69 | if #available(iOS 13.0, *) {
70 | guard let window = presenter()?.viewIfLoaded?.window else {
71 | throw RxModalError.missingPresenter
72 | }
73 | self.window = window
74 | self.session.presentationContextProvider = self
75 | }
76 |
77 | self.session.start()
78 | }
79 |
80 | func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
81 | return window
82 | }
83 |
84 | public func dispose() {
85 | session.cancel()
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/Sources/Pickers/MPMediaPickerController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MPMediaPickerController.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | //
7 |
8 | #if canImport(MediaPlayer)
9 | import UIKit
10 | import MediaPlayer
11 | import RxSwift
12 | import RxCocoa
13 |
14 | @available(iOS 9.3, *)
15 | extension RxModal {
16 | public static var mediaLibraryAuthorizationStatus: Single {
17 | Single.deferred {
18 | let status = MPMediaLibrary.authorizationStatus()
19 | guard case .notDetermined = status else {
20 | return .just(status)
21 | }
22 | return Single.create { observer in
23 | MPMediaLibrary.requestAuthorization { status in
24 | observer(.success(status))
25 | }
26 | return Disposables.create()
27 | }
28 | }
29 | }
30 |
31 | /**
32 | Media Picker
33 |
34 | Requires `NSAppleMusicUsageDescription` key in App's `Info.plist`
35 | */
36 | public static func mediaPicker(presenter: Presenter = .keyWindow, configuration: @escaping (MPMediaPickerController) -> Void = { _ in }) -> Single {
37 | MPMediaPickerControllerCoordinator.present(using: presenter) { delegate in
38 | MPMediaPickerController(mediaTypes: .any)..{
39 | configuration($0)
40 | $0.delegate = delegate
41 | }
42 | } sequence: {
43 | $0.subject.asSingle()
44 | }
45 | .require(mediaLibraryAuthorizationStatus, in: .authorized, .restricted)
46 | }
47 | }
48 |
49 | private class MPMediaPickerControllerCoordinator: RxModalCoordinator, MPMediaPickerControllerDelegate {
50 | required init() {}
51 |
52 | let subject = PublishSubject()
53 |
54 | func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
55 | subject.onNext(mediaItemCollection)
56 | subject.onCompleted()
57 | }
58 |
59 | func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
60 | subject.onNext(MPMediaItemCollection(items: []))
61 | subject.onCompleted()
62 | }
63 | }
64 | #endif
65 |
--------------------------------------------------------------------------------
/Sources/Pickers/PHPickerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PHPickerViewController.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | //
7 |
8 | #if canImport(PhotosUI)
9 | import UIKit
10 | import PhotosUI
11 | import RxSwift
12 | import RxCocoa
13 |
14 | extension RxModal {
15 | @available(iOS 14, *)
16 | public static func photoPicker(presenter: Presenter = .keyWindow, configuration: @escaping (inout PHPickerConfiguration) -> Void = { _ in }) -> Single<[PHPickerResult]> {
17 | PHPickerViewControllerCoordinator.present(using: presenter) { delegate in
18 | PHPickerViewController(configuration: PHPickerConfiguration() .. configuration)..{
19 | $0.delegate = delegate
20 | }
21 | } sequence: {
22 | $0.pickerResults.asSingle()
23 | }
24 | }
25 | }
26 |
27 | @available(iOS 14, *)
28 | private class PHPickerViewControllerCoordinator: RxModalCoordinator, PHPickerViewControllerDelegate {
29 | required init() {}
30 |
31 | let pickerResults = PublishSubject<[PHPickerResult]>()
32 |
33 | func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
34 | pickerResults.onNext(results)
35 | pickerResults.onCompleted()
36 | }
37 | }
38 | #endif
39 |
--------------------------------------------------------------------------------
/Sources/Presenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Presenter.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 05/02/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | public struct Presenter {
11 | private let get: () -> UIViewController?
12 |
13 | public static let keyWindow = Presenter {
14 | if #available(iOS 13.0, *) {
15 | let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
16 | assert(scenes.count <= 1, "Several connected scenes. You probably want to use a more specific presenter.")
17 | let windows = scenes.first?.windows.filter { $0.isKeyWindow } ?? []
18 | assert(windows.count <= 1, "Several windows found in the scene. You probably want to use a more specific presenter.")
19 | return windows.first?.rootViewController
20 | } else {
21 | return UIApplication.shared.keyWindow?.rootViewController
22 | }
23 | }
24 |
25 | public static func window(_ window: UIWindow?) -> Presenter {
26 | Presenter { [weak window] in
27 | window?.rootViewController
28 | }
29 | }
30 |
31 | public static func viewController(_ viewController: UIViewController?) -> Presenter {
32 | Presenter { [weak viewController] in
33 | viewController
34 | }
35 | }
36 |
37 | public static func view(_ view: UIView?) -> Presenter {
38 | Presenter { [weak view] in
39 | view?.window?.rootViewController
40 | }
41 | }
42 |
43 | @available(iOS 13.0, *)
44 | public static func scene(_ scene: UIWindowScene) -> Presenter {
45 | Presenter { [weak scene] in
46 | guard let scene = scene else { return nil }
47 | assert(scene.windows.count <= 1, "Several windows found in the scene. You probably want to use a more specific presenter.")
48 | return scene.windows.first?.rootViewController
49 | }
50 | }
51 |
52 | public func callAsFunction() -> UIViewController? {
53 | get()
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Rx+AuthorizationStatus.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Rx+AuthorizationStatus.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 05/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxSwift
10 |
11 | // MARK: - Completable
12 |
13 | extension PrimitiveSequence where Trait == CompletableTrait, Element == Never {
14 | public func require(_ status: Single, in expectedStatus: T...) -> Completable {
15 | status.flatMapCompletable { status in
16 | guard expectedStatus.contains(status) else {
17 | return .error(RxModalError.authorizationDenied(T.self))
18 | }
19 | return self
20 | }
21 | }
22 | }
23 |
24 | // MARK: - Single
25 |
26 | extension PrimitiveSequence where Trait == SingleTrait {
27 | public func require(_ status: Single, in expectedStatus: T...) -> Single {
28 | status.flatMap { status -> Single in
29 | guard expectedStatus.contains(status) else {
30 | return .error(RxModalError.authorizationDenied(T.self))
31 | }
32 | return self
33 | }
34 | }
35 | }
36 |
37 | // MARK: - Maybe
38 |
39 | extension PrimitiveSequence where Trait == MaybeTrait {
40 | public func require(_ status: Single, in expectedStatus: T...) -> Maybe {
41 | status.flatMapMaybe { status in
42 | guard expectedStatus.contains(status) else {
43 | return .error(RxModalError.authorizationDenied(T.self))
44 | }
45 | return self
46 | }
47 | }
48 | }
49 |
50 | // MARK: - Observable
51 |
52 | extension Observable {
53 | public func require(_ status: Single, in expectedStatus: T...) -> Observable {
54 | status.asObservable().flatMap { status -> Observable in
55 | guard expectedStatus.contains(status) else {
56 | return .error(RxModalError.authorizationDenied(T.self))
57 | }
58 | return self
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/RxModal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxModal.swift
3 | // RxSwiftCommunity
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | // Copyright © 2021 RxSwiftCommunity. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxSwift
11 |
12 | public enum RxModal {
13 |
14 | }
15 |
16 | public enum RxModalError: Error {
17 | case missingPresenter
18 | case unsupported
19 | case authorizationDenied(Any.Type)
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/RxModalCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxModalCoordinator.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 05/02/2021.
6 | //
7 |
8 | import UIKit
9 | import RxSwift
10 |
11 | open class RxModalCoordinator: NSObject, Disposable {
12 | private var _viewController: ViewController?
13 | public var viewController: ViewController {
14 | _viewController!
15 | }
16 |
17 | required public override init() {}
18 |
19 | open func present(_ controller: @autoclosure () -> ViewController, with presenter: Presenter) throws {
20 | guard let presenter = presenter() else {
21 | throw RxModalError.missingPresenter
22 | }
23 | _viewController = controller()
24 | presenter.present(viewController, animated: true, completion: nil)
25 | }
26 |
27 | open func dispose() {
28 | guard viewController.isBeingDismissed == false else {
29 | return
30 | }
31 | viewController.presentingViewController?.dismiss(animated: true, completion: nil)
32 | }
33 | }
34 |
35 | extension NSObjectProtocol {
36 |
37 | //MARK: - Completable
38 |
39 | public static func present(
40 | using presenter: Presenter = .keyWindow,
41 | controllerFactory: @escaping (Self) -> ViewController,
42 | sequence: @escaping (Self) -> Completable
43 | ) -> Completable where Self: RxModalCoordinator {
44 | Completable.using {
45 | let coordinator = Self.init()
46 | try coordinator.present(controllerFactory(coordinator), with: presenter)
47 | return coordinator
48 | } primitiveSequenceFactory: { coordinator in
49 | sequence(coordinator)
50 | }
51 | .subscribe(on: MainScheduler.instance)
52 |
53 | }
54 |
55 | //MARK: - Single
56 |
57 | public static func present(
58 | using presenter: Presenter = .keyWindow,
59 | controllerFactory: @escaping (Self) -> ViewController,
60 | sequence: @escaping (Self) -> Single
61 | ) -> Single where Self: RxModalCoordinator {
62 | Single.using {
63 | let coordinator = Self.init()
64 | try coordinator.present(controllerFactory(coordinator), with: presenter)
65 | return coordinator
66 | } primitiveSequenceFactory: { coordinator in
67 | sequence(coordinator)
68 | }
69 | .subscribe(on: MainScheduler.instance)
70 | }
71 |
72 | //MARK: - Maybe
73 |
74 | public static func present(
75 | using presenter: Presenter = .keyWindow,
76 | controllerFactory: @escaping (Self) -> ViewController,
77 | sequence: @escaping (Self) -> Maybe
78 | ) -> Maybe where Self: RxModalCoordinator {
79 | Maybe.using {
80 | let coordinator = Self.init()
81 | try coordinator.present(controllerFactory(coordinator), with: presenter)
82 | return coordinator
83 | } primitiveSequenceFactory: { coordinator in
84 | sequence(coordinator)
85 | }
86 | .subscribe(on: MainScheduler.instance)
87 | }
88 |
89 | //MARK: - Observable
90 |
91 | public static func present(
92 | using presenter: Presenter = .keyWindow,
93 | controllerFactory: @escaping (Self) -> ViewController,
94 | sequence: @escaping (Self) -> Observable
95 | ) -> Observable where Self: RxModalCoordinator {
96 | Observable.using {
97 | let coordinator = Self.init()
98 | try coordinator.present(controllerFactory(coordinator), with: presenter)
99 | return coordinator
100 | } observableFactory: { coordinator in
101 | sequence(coordinator)
102 | }
103 | .subscribe(on: MainScheduler.instance)
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/Sources/RxModalDescription.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxModalDescription.swift
3 | // RxModal
4 | //
5 | // Created by Jérôme Alves on 06/02/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | public protocol RxModalCustomStringConvertible {
11 | var rxModalDescription: String { get }
12 | }
13 |
14 | extension String {
15 | public init(rxModalDescribing value: Any) {
16 | if let value = value as? RxModalCustomStringConvertible {
17 | self = value.rxModalDescription
18 | } else {
19 | self = String(describing: value)
20 | }
21 | }
22 | }
23 |
24 | #if canImport(MessageUI)
25 | import MessageUI
26 | extension MFMailComposeResult: RxModalCustomStringConvertible {
27 | public var rxModalDescription: String {
28 | switch self {
29 | case .cancelled:
30 | return "cancelled"
31 | case .saved:
32 | return "saved"
33 | case .sent:
34 | return "sent"
35 | case .failed:
36 | return "failed"
37 | @unknown default:
38 | return "@unknown"
39 | }
40 | }
41 | }
42 |
43 | extension MessageComposeResult: RxModalCustomStringConvertible {
44 | public var rxModalDescription: String {
45 | switch self {
46 | case .cancelled:
47 | return "cancelled"
48 | case .sent:
49 | return "sent"
50 | case .failed:
51 | return "failed"
52 | @unknown default:
53 | return "@unknown"
54 | }
55 | }
56 | }
57 | #endif
58 |
59 | #if canImport(MediaPlayer)
60 | import MediaPlayer
61 | @available(iOS 9.3, *)
62 | extension MPMediaLibraryAuthorizationStatus: RxModalCustomStringConvertible {
63 | public var rxModalDescription: String {
64 | switch self {
65 | case .notDetermined:
66 | return "notDetermined"
67 | case .denied:
68 | return "denied"
69 | case .restricted:
70 | return "restricted"
71 | case .authorized:
72 | return "authorized"
73 | @unknown default:
74 | return "@unknown"
75 | }
76 | }
77 | }
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import RxModalTests
3 |
4 | XCTMain([
5 | testCase(RxModalTests.allTests),
6 | ])
7 |
--------------------------------------------------------------------------------
/Tests/RxModalTests/RxModalTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxModalTests.swift
3 | // RxSwiftCommunity
4 | //
5 | // Created by Jérôme Alves on 03/02/2021.
6 | // Copyright © 2021 RxSwiftCommunity. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | import RxModal
12 |
13 | class RxModalTests: XCTestCase {
14 | func testExample() {
15 | // This is an example of a functional test case.
16 | // Use XCTAssert and related functions to verify your tests produce the correct results.
17 | //// XCTAssertEqual(RxModal().text, "Hello, World!")
18 | }
19 |
20 | static var allTests = [
21 | ("testExample", testExample),
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/assets/RxModal_Demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/assets/RxModal_Demo.gif
--------------------------------------------------------------------------------
/assets/RxModal_Icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxModal/ff3e03221a827a2a87559a240acdb27d6d557453/assets/RxModal_Icons.png
--------------------------------------------------------------------------------