Skip to content

Commit 01f33ce

Browse files
Merge pull request #121 from wwt/fullScreenCover
Adds support for Full screen cover modal presentation style
2 parents 7cd7b21 + 9fd2f94 commit 01f33ce

15 files changed

Lines changed: 751 additions & 20 deletions

File tree

.github/SwiftCurrentLint/.swiftlint.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ included: # paths to include during linting. `--path` is ignored if present.
127127
- ../../Sources
128128
- ../../ExampleApps/SwiftUIExample
129129
# - ../../Tests
130-
# excluded: # paths to ignore during linting. Takes precedence over `included`.
131-
# - Workflow/.build/
130+
excluded: # paths to ignore during linting. Takes precedence over `included`.
131+
- ../../ExampleApps/SwiftUIExample/SwiftCurrent_SwiftUI_UITests
132+
- ../../ExampleApps/SwiftUIExample/SwiftUIExample/TestViews
132133
# - Workflow/.swiftpm/
133134
# - Workflow/Package.swift
134135

.github/guides/Working with Modals.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,16 @@ With that you've described that `FirstView` should be presented normally. When i
1717
> NOTE: Unlike `LaunchStyle.SwiftUI.PresentationType.navigationLink` you apply `LaunchStyle.SwiftUI.PresentationType.modal` to a view that should be launched modally.
1818
1919
### Different Modal Styles
20-
As of right now presenting modals with sheets is the only supported modal style by SwiftCurrent. If you need a workaround you'll have to split your workflow into 2 sub-workflows and use `fullScreenCover` yourself. [Issue: #119](https://github.com/wwt/SwiftCurrent/issues/119) is tracking a feature request to add support for `fullScreenCover`.
20+
When you use a presentation type of `LaunchStyle.SwiftUI.PresentationType.modal` you can optionally pass it a `LaunchStyle.SwiftUI.ModalPresentationStyle`.
21+
22+
#### Example:
23+
The following will use a full screen cover:
24+
```swift
25+
NavigationView {
26+
WorkflowLauncher(isLaunched: .constant(true)) {
27+
thenProceed(with: FirstView.self) {
28+
thenProceed(with: SecondView.self).presentationType(.modal(.fullScreenCover))
29+
}
30+
}
31+
}
32+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>$(DEVELOPMENT_LANGUAGE)</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleVersion</key>
20+
<string>1</string>
21+
</dict>
22+
</plist>
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//
2+
// SwiftCurrent_SwiftUI_UITests.swift
3+
// SwiftCurrent_SwiftUI_UITests
4+
//
5+
// Created by Richard Gist on 9/1/21.
6+
// Copyright © 2021 WWT and Tyler Thompson. All rights reserved.
7+
//
8+
9+
import XCTest
10+
11+
class SwiftCurrent_SwiftUI_UITests: XCTestCase {
12+
13+
override func setUpWithError() throws {
14+
// In UI tests it is usually best to stop immediately when a failure occurs.
15+
continueAfterFailure = false
16+
}
17+
18+
func testBackingUpWithDefaultModals() throws {
19+
// UI tests must launch the application that they test.
20+
let app = XCUIApplication()
21+
app.launch (
22+
.xcuiTest(true),
23+
.testingView(.fourItemWorkflow),
24+
.presentationType(.FR2, .modal),
25+
.presentationType(.FR3, .modal),
26+
.presentationType(.FR4, .modal)
27+
)
28+
29+
XCTAssert(app.staticTexts["This is FR1"].exists)
30+
app.buttons.matching(identifier: "Navigate forward").lastMatch.tap()
31+
32+
XCTAssert(app.staticTexts["This is FR2"].exists)
33+
app.buttons.matching(identifier: "Navigate forward").lastMatch.tap()
34+
35+
XCTAssert(app.staticTexts["This is FR3"].exists)
36+
app.buttons.matching(identifier: "Navigate forward").lastMatch.tap()
37+
38+
XCTAssert(app.staticTexts["This is FR4"].exists)
39+
app.buttons.matching(identifier: "Navigate backward").lastMatch.tap()
40+
41+
XCTAssert(app.staticTexts["This is FR3"].exists)
42+
app.buttons.matching(identifier: "Navigate backward").lastMatch.tap()
43+
44+
XCTAssert(app.staticTexts["This is FR2"].exists)
45+
app.buttons.matching(identifier: "Navigate backward").lastMatch.tap()
46+
47+
XCTAssert(app.staticTexts["This is FR1"].exists)
48+
}
49+
50+
func testBackingUpWithFullScreenCovers() throws {
51+
// UI tests must launch the application that they test.
52+
let app = XCUIApplication()
53+
app.launch (
54+
.xcuiTest(true),
55+
.testingView(.fourItemWorkflow),
56+
.presentationType(.FR2, .modal(.fullScreenCover)),
57+
.presentationType(.FR3, .modal(.fullScreenCover)),
58+
.presentationType(.FR4, .modal(.fullScreenCover))
59+
)
60+
61+
XCTAssert(app.staticTexts["This is FR1"].exists)
62+
app.buttons.matching(identifier: "Navigate forward").firstMatch.tap()
63+
64+
XCTAssert(app.staticTexts["This is FR2"].exists)
65+
app.buttons.matching(identifier: "Navigate forward").firstMatch.tap()
66+
67+
XCTAssert(app.staticTexts["This is FR3"].exists)
68+
app.buttons.matching(identifier: "Navigate forward").element(boundBy: 1).tap()
69+
70+
XCTAssert(app.staticTexts["This is FR4"].exists)
71+
app.buttons.matching(identifier: "Navigate backward").element(boundBy: 2).tap()
72+
73+
XCTAssert(app.staticTexts["This is FR3"].exists)
74+
app.buttons.matching(identifier: "Navigate backward").element(boundBy: 1).tap()
75+
76+
XCTAssert(app.staticTexts["This is FR2"].exists)
77+
app.buttons.matching(identifier: "Navigate backward").firstMatch.tap()
78+
79+
XCTAssert(app.staticTexts["This is FR1"].exists)
80+
}
81+
82+
func testBackingUpWithNavigationLinks() throws {
83+
// UI tests must launch the application that they test.
84+
let app = XCUIApplication()
85+
app.launch(
86+
.xcuiTest(true),
87+
.embedInNavStack(true),
88+
.testingView(.fourItemWorkflow),
89+
.presentationType(.FR1, .navigationLink),
90+
.presentationType(.FR2, .navigationLink),
91+
.presentationType(.FR3, .navigationLink)
92+
)
93+
94+
XCTAssert(app.staticTexts["This is FR1"].exists)
95+
app.buttons["Navigate forward"].tap()
96+
97+
XCTAssert(app.staticTexts["This is FR2"].exists)
98+
app.buttons["Navigate forward"].tap()
99+
100+
XCTAssert(app.staticTexts["This is FR3"].exists)
101+
app.buttons["Navigate forward"].tap()
102+
103+
XCTAssert(app.staticTexts["This is FR4"].exists)
104+
app.buttons["Navigate backward"].tap()
105+
106+
XCTAssert(app.staticTexts["This is FR3"].exists)
107+
app.buttons["Navigate backward"].tap()
108+
109+
XCTAssert(app.staticTexts["This is FR2"].exists)
110+
app.buttons["Navigate backward"].tap()
111+
112+
XCTAssert(app.staticTexts["This is FR1"].exists)
113+
}
114+
}
115+
116+
extension XCUIApplication {
117+
func launch(_ environment: Environment...) {
118+
var launchEnvironment = [String: String]()
119+
environment.forEach { launchEnvironment = launchEnvironment + $0.dictionaryValue }
120+
self.launchEnvironment = launchEnvironment
121+
launch()
122+
}
123+
}
124+
125+
public extension Dictionary {
126+
static func + (lhs: [Key: Value], rhs: [Key: Value]) -> [Key: Value] {
127+
return lhs.merging(rhs, uniquingKeysWith: { $1 })
128+
}
129+
}
130+
131+
extension XCUIElementQuery {
132+
var lastMatch: XCUIElement { return self.element(boundBy: self.count - 1) }
133+
}

0 commit comments

Comments
 (0)