Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ViewEnvironment (#739) #999

Merged
merged 2 commits into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions docs/tutorial/building-a-view-controller-from-screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ controller from a view model update.
struct DemoScreen: Screen {
let title: String
let onTap: () -> Void

func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return DemoScreenViewController.description(for: self, environment: environment)
}
}


class DemoScreenViewController: ScreenViewController<DemoScreen> {

private let button: UIButton

required init(screen: DemoScreen) {
required init(screen: DemoScreen, environment: ViewEnvironment) {
button = UIButton()
super.init(screen: screen)
super.init(screen: screen, environment: environment)

update(screen: screen)
}
Expand All @@ -39,8 +43,8 @@ class DemoScreenViewController: ScreenViewController<DemoScreen> {
button.frame = view.bounds
}

override func screenDidChange(from previousScreen: DemoScreen) {
super.screenDidChange(from: previousScreen)
override func screenDidChange(from previousScreen: DemoScreen, previousEnvironment: ViewEnvironment) {
super.screenDidChange(from: previousScreen, previousEnvironment: previousEnvironment)
update(screen: screen)
}

Expand All @@ -64,5 +68,5 @@ class DemoScreenViewController: ScreenViewController<DemoScreen> {
1. The button is tapped. When the callback is called, we call the `onTap` closure passed into the
screen. The workflow will handle this event, update its state, and a new screen will be rendered.
1. The updated screen is passed to the view controller via the
`screenDidChange(from previousScreen:)` method. Again, the view controller updates the title of
the button based on what was passed in the screen.
`screenDidChange(from previousScreen: previousEnvironment: previousEnvironment:)` method. Again,
the view controller updates the title of the button based on what was passed in the screen.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import WorkflowUI
public final class BackStackContainer: ScreenViewController<BackStackScreen>, UINavigationControllerDelegate {
private let navController: UINavigationController

public required init(screen: BackStackScreen) {
public required init(screen: BackStackScreen, environment: ViewEnvironment) {
self.navController = UINavigationController()

super.init(screen: screen)
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand All @@ -42,7 +42,7 @@ public final class BackStackContainer: ScreenViewController<BackStackScreen>, UI
navController.view.frame = view.bounds
}

public override func screenDidChange(from previousScreen: BackStackScreen) {
public override func screenDidChange(from previousScreen: BackStackScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand All @@ -63,10 +63,10 @@ public final class BackStackContainer: ScreenViewController<BackStackScreen>, UI
viewController.matches(item: item)
}) {
let existingViewController = existingViewControllers.remove(at: idx)
existingViewController.update(item: item)
existingViewController.update(item: item, environment: environment)
updatedViewControllers.append(existingViewController)
} else {
updatedViewControllers.append(ScreenWrapperViewController(item: item))
updatedViewControllers.append(ScreenWrapperViewController(item: item, environment: environment))
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public struct BackStackScreen: Screen {
self.items = items
}

public var viewControllerDescription: ViewControllerDescription {
return BackStackContainer.description(for: self)
public func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return BackStackContainer.description(for: self, environment: environment)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import WorkflowUI
final class ScreenWrapperViewController: UIViewController {
let key: AnyHashable
let screenType: Any.Type
let environment: ViewEnvironment

let contentViewController: DescribedViewController

init(item: BackStackScreen.Item) {
init(item: BackStackScreen.Item, environment: ViewEnvironment) {
self.key = item.key
self.screenType = item.screenType
self.contentViewController = DescribedViewController(screen: item.screen)
self.environment = environment
self.contentViewController = DescribedViewController(screen: item.screen, environment: environment)

super.init(nibName: nil, bundle: nil)

Expand All @@ -51,8 +53,8 @@ final class ScreenWrapperViewController: UIViewController {
contentViewController.view.frame = view.bounds
}

func update(item: BackStackScreen.Item) {
contentViewController.update(screen: item.screen)
func update(item: BackStackScreen.Item, environment: ViewEnvironment) {
contentViewController.update(screen: item.screen, environment: environment)
update(barVisibility: item.barVisibility)
}

Expand Down
16 changes: 8 additions & 8 deletions swift/Samples/SampleApp/Sources/CrossFadeContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ struct CrossFadeScreen: Screen {
return self.key == otherScreen.key
}

var viewControllerDescription: ViewControllerDescription {
return CrossFadeContainerViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return CrossFadeContainerViewController.description(for: self, environment: environment)
}
}


fileprivate final class CrossFadeContainerViewController: ScreenViewController<CrossFadeScreen> {
var childViewController: DescribedViewController

required init(screen: CrossFadeScreen) {
childViewController = DescribedViewController(screen: screen.baseScreen)
super.init(screen: screen)
required init(screen: CrossFadeScreen, environment: ViewEnvironment) {
childViewController = DescribedViewController(screen: screen.baseScreen, environment: environment)
super.init(screen: screen, environment: environment)
}

override func viewDidLoad() {
Expand All @@ -67,13 +67,13 @@ fileprivate final class CrossFadeContainerViewController: ScreenViewController<C
childViewController.view.frame = view.bounds
}

override func screenDidChange(from previousScreen: CrossFadeScreen) {
override func screenDidChange(from previousScreen: CrossFadeScreen, previousEnvironment: ViewEnvironment) {
if screen.isEquivalent(to: previousScreen) {
childViewController.update(screen: screen.baseScreen)
childViewController.update(screen: screen.baseScreen, environment: environment)
} else {
// The new screen is different than the previous. Animate the transition.
let oldChild = childViewController
childViewController = DescribedViewController(screen: screen.baseScreen)
childViewController = DescribedViewController(screen: screen.baseScreen, environment: environment)
addChild(childViewController)
view.addSubview(childViewController.view)
UIView.transition(
Expand Down
10 changes: 5 additions & 5 deletions swift/Samples/SampleApp/Sources/DemoScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ struct DemoScreen: Screen {
let isRefreshEnabled: Bool
let onRefreshTap: () -> Void

var viewControllerDescription: ViewControllerDescription {
return DemoViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return DemoViewController.description(for: self, environment: environment)
}
}

Expand All @@ -42,12 +42,12 @@ fileprivate final class DemoViewController: ScreenViewController<DemoScreen> {
private let statusLabel: UILabel
private let refreshButton: UIButton

required init(screen: DemoScreen) {
required init(screen: DemoScreen, environment: ViewEnvironment) {
titleButton = UIButton(frame: .zero)
subscribeButton = UIButton(frame: .zero)
statusLabel = UILabel(frame: .zero)
refreshButton = UIButton(frame: .zero)
super.init(screen: screen)
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand Down Expand Up @@ -106,7 +106,7 @@ fileprivate final class DemoViewController: ScreenViewController<DemoScreen> {
height: height)
}

override func screenDidChange(from previousScreen: DemoScreen) {
override func screenDidChange(from previousScreen: DemoScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand Down
10 changes: 5 additions & 5 deletions swift/Samples/SampleApp/Sources/WelcomeScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct WelcomeScreen: Screen {
var onNameChanged: (String) -> Void
var onLoginTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return WelcomeViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return WelcomeViewController.description(for: self, environment: environment)
}
}

Expand All @@ -33,11 +33,11 @@ fileprivate final class WelcomeViewController: ScreenViewController<WelcomeScree
let nameField: UITextField
let button: UIButton

required init(screen: WelcomeScreen) {
required init(screen: WelcomeScreen, environment: ViewEnvironment) {
welcomeLabel = UILabel(frame: .zero)
nameField = UITextField(frame: .zero)
button = UIButton(frame: .zero)
super.init(screen: screen)
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand Down Expand Up @@ -89,7 +89,7 @@ fileprivate final class WelcomeViewController: ScreenViewController<WelcomeScree
.insetBy(dx: inset, dy: 0.0)
}

override func screenDidChange(from previousScreen: WelcomeScreen) {
override func screenDidChange(from previousScreen: WelcomeScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand Down
12 changes: 6 additions & 6 deletions swift/Samples/SplitScreenContainer/DemoApp/BarScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct BarScreen: Screen {
let backgroundColors: [UIColor]
let viewTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return BarScreenViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return BarScreenViewController.description(for: self, environment: environment)
}
}

Expand All @@ -34,8 +34,8 @@ fileprivate final class BarScreenViewController: ScreenViewController<BarScreen>
private lazy var tapGestureRecognizer: UITapGestureRecognizer = .init()
private var gradientLayer: CAGradientLayer?

required init(screen: BarScreen) {
super.init(screen: screen)
required init(screen: BarScreen, environment: ViewEnvironment) {
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand All @@ -58,8 +58,8 @@ fileprivate final class BarScreenViewController: ScreenViewController<BarScreen>

updateGradient(for: view, colors: screen.backgroundColors)
}
override func screenDidChange(from previousScreen: BarScreen) {

override func screenDidChange(from previousScreen: BarScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand Down
12 changes: 6 additions & 6 deletions swift/Samples/SplitScreenContainer/DemoApp/FooScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct FooScreen: Screen {
let backgroundColor: UIColor
let viewTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return FooScreenViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return FooScreenViewController.description(for: self, environment: environment)
}
}

Expand All @@ -33,8 +33,8 @@ fileprivate final class FooScreenViewController: ScreenViewController<FooScreen>
private lazy var titleLabel: UILabel = .init()
private lazy var tapGestureRecognizer: UITapGestureRecognizer = .init()

required init(screen: FooScreen) {
super.init(screen: screen)
required init(screen: FooScreen, environment: ViewEnvironment) {
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand All @@ -54,8 +54,8 @@ fileprivate final class FooScreenViewController: ScreenViewController<FooScreen>
titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
override func screenDidChange(from previousScreen: FooScreen) {

override func screenDidChange(from previousScreen: FooScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class SplitScreenContainerScreenSnapshotTests: FBSnapshotTestCase {
)

let viewController = SplitScreenContainerViewController(
screen: splitScreenContainerScreen
screen: splitScreenContainerScreen,
environment: .empty
)
viewController.view.layoutIfNeeded()

Expand All @@ -44,8 +45,8 @@ fileprivate struct FooScreen: Screen {
let backgroundColor: UIColor
let viewTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return FooScreenViewController.description(for: self)
func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return FooScreenViewController.description(for: self, environment: environment)
}
}

Expand All @@ -55,8 +56,8 @@ fileprivate final class FooScreenViewController: ScreenViewController<FooScreen>
private lazy var titleLabel: UILabel = .init()
private lazy var tapGestureRecognizer: UITapGestureRecognizer = .init()

required init(screen: FooScreen) {
super.init(screen: screen)
required init(screen: FooScreen, environment: ViewEnvironment) {
super.init(screen: screen, environment: environment)

update(with: screen)
}
Expand All @@ -76,8 +77,8 @@ fileprivate final class FooScreenViewController: ScreenViewController<FooScreen>
titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
override func screenDidChange(from previousScreen: FooScreen) {

override func screenDidChange(from previousScreen: FooScreen, previousEnvironment: ViewEnvironment) {
update(with: screen)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2020 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import WorkflowUI

public enum SplitScreenPosition {
/// Not appearing in a split screen context
case none

/// Appearing in the leading position in a split screen
case leading

/// Appearing in the trailing position in a split screen
case trailing
}

extension ViewEnvironment {

internal(set) public var splitScreenPosition: SplitScreenPosition {
get { return self[SplitScreenPositionKey.self] }
set { self[SplitScreenPositionKey.self] = newValue }
}

}

private enum SplitScreenPositionKey: ViewEnvironmentKey {
static var defaultValue: SplitScreenPosition = .none
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool! I'm kinda blown away that a private type's internal static var is accessible from outside this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SplitScreenPositionKey is not accessed from outside this file.

Copy link
Contributor

@JustinDSN JustinDSN Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's defaultValue var is.

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public struct SplitScreenContainerScreen<LeadingScreenType: Screen, TrailingScre
self.separatorWidth = separatorWidth
}

public var viewControllerDescription: ViewControllerDescription {
return SplitScreenContainerViewController.description(for: self)
public func viewControllerDescription(environment: ViewEnvironment) -> ViewControllerDescription {
return SplitScreenContainerViewController.description(for: self, environment: environment)
}

}
Expand Down
Loading