Skip to content

Commit

Permalink
Merge pull request #999 from square/bc/view-environment
Browse files Browse the repository at this point in the history
Add ViewEnvironment (#739)
  • Loading branch information
bencochran authored Mar 5, 2020
2 parents 99ddffb + 6a46f0e commit 9b38efd
Show file tree
Hide file tree
Showing 43 changed files with 417 additions and 232 deletions.
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
}
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

0 comments on commit 9b38efd

Please sign in to comment.