Rename `left` and `right` to `leading` and `trailing` and respect layout direction.
MODIFY
swift/Samples/SplitScreenContainer/DemoApp/DemoWorkflow.swift
swift/Samples/SplitScreenContainer/DemoApp/DemoWorkflow.swift
@@ -76,8 +76,8 @@ extension DemoWorkflow {
let sink = context.makeSink(of: Action.self)
return SplitScreenContainerScreen(
- leftScreen: leftScreenFor(state: state, context: context),
- rightScreen: FooScreen(title: "Right screen", backgroundColor: .green, viewTapped: { sink.send(.viewTapped) }),
+ leadingScreen: leadingScreenFor(state: state, context: context),
+ trailingScreen: FooScreen(title: "Trailing screen", backgroundColor: .green, viewTapped: { sink.send(.viewTapped) }),
ratio: DemoWorkflow.sizes[state % DemoWorkflow.sizes.count],
separatorColor: .black,
separatorWidth: 1.0 * CGFloat(state)
@@ -85,7 +85,7 @@ extension DemoWorkflow {
}
- private func leftScreenFor(state: State, context: RenderContext<DemoWorkflow>) -> AnyScreen {
+ private func leadingScreenFor(state: State, context: RenderContext<DemoWorkflow>) -> AnyScreen {
let sink = context.makeSink(of: Action.self)
let color = DemoWorkflow.colors[state % DemoWorkflow.colors.count]
@@ -93,7 +93,7 @@ extension DemoWorkflow {
if state % 2 == 0 {
return AnyScreen(
FooScreen(
- title: "Left Foo screen",
+ title: "Leading Foo screen",
backgroundColor: color,
viewTapped: { sink.send(.viewTapped) }
)
@@ -103,7 +103,7 @@ extension DemoWorkflow {
return AnyScreen(
BarScreen(
- title: "Left Bar screen",
+ title: "Leading Bar screen",
backgroundColors: [color, complimentaryColor],
viewTapped: { sink.send(.viewTapped) }
)

MODIFY
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_custom@2x.png
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_custom@2x.png
Binary files a/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_custom@2x.png and b/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_custom@2x.png differ

MODIFY
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_half@2x.png
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_half@2x.png
Binary files a/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_half@2x.png and b/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_half@2x.png differ

MODIFY
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_quarter@2x.png
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_quarter@2x.png
Binary files a/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_quarter@2x.png and b/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_quarter@2x.png differ

MODIFY
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_third@2x.png
swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_third@2x.png
Binary files a/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_third@2x.png and b/swift/Samples/SplitScreenContainer/SnapshotTests/ReferenceImages_64/SplitScreenContainer_Unit_SnapshotTests.SplitScreenContainerScreenSnapshotTests/test_splitRatio_third@2x.png differ

MODIFY
swift/Samples/SplitScreenContainer/SnapshotTests/SplitScreenContainerScreenSnapshotTests.swift
swift/Samples/SplitScreenContainer/SnapshotTests/SplitScreenContainerScreenSnapshotTests.swift
@@ -13,7 +13,7 @@ class SplitScreenContainerScreenSnapshotTests: FBSnapshotTestCase {
func test_splitRatio() {
var viewRegistry = ViewRegistry()
- viewRegistry.register(screenViewControllerType: BaseScreenViewController.self)
+ viewRegistry.register(screenViewControllerType: FooScreenViewController.self)
let ratios: [String : CGFloat] = [
"third" : .third,
@@ -24,8 +24,8 @@ class SplitScreenContainerScreenSnapshotTests: FBSnapshotTestCase {
for (name, ratio) in ratios {
let splitScreenContainerScreen = SplitScreenContainerScreen(
- leftScreen: BaseScreen(title: "Left screen", backgroundColor: .green),
- rightScreen: BaseScreen(title: "Right screen", backgroundColor: .red),
+ leadingScreen: FooScreen(title: "Leading screen", backgroundColor: .green, viewTapped: {}),
+ trailingScreen: FooScreen(title: "Trailing screen", backgroundColor: .red, viewTapped: {}),
ratio: ratio
)
@@ -41,20 +41,19 @@ class SplitScreenContainerScreenSnapshotTests: FBSnapshotTestCase {
}
-struct BaseScreen: Screen {
- var title: String
- var backgroundColor: UIColor
+fileprivate struct FooScreen: Screen {
+ let title: String
+ let backgroundColor: UIColor
+ let viewTapped: () -> Void
}
-fileprivate final class BaseScreenViewController: ScreenViewController<BaseScreen> {
+fileprivate final class FooScreenViewController: ScreenViewController<FooScreen> {
- private let titleLabel: UILabel
-
- required init(screen: BaseScreen, viewRegistry: ViewRegistry) {
- titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
- titleLabel.textAlignment = .center
+ private lazy var titleLabel: UILabel = .init()
+ private lazy var tapGestureRecognizer: UITapGestureRecognizer = .init()
+ required init(screen: FooScreen, viewRegistry: ViewRegistry) {
super.init(screen: screen, viewRegistry: viewRegistry)
update(with: screen)
@@ -63,22 +62,31 @@ fileprivate final class BaseScreenViewController: ScreenViewController<BaseScree
override func viewDidLoad() {
super.viewDidLoad()
- view.addSubview(titleLabel)
- }
+ tapGestureRecognizer.addTarget(self, action: #selector(viewTapped))
+ view.addGestureRecognizer(tapGestureRecognizer)
- override func viewDidLayoutSubviews() {
- super.viewDidLayoutSubviews()
+ titleLabel.translatesAutoresizingMaskIntoConstraints = false
+ titleLabel.textAlignment = .center
+ view.addSubview(titleLabel)
- titleLabel.center = view.center
+ NSLayoutConstraint.activate([
+ titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
+ titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
+ ])
}
- override func screenDidChange(from previousScreen: BaseScreen) {
+ override func screenDidChange(from previousScreen: FooScreen) {
update(with: screen)
}
- private func update(with screen: BaseScreen) {
+ private func update(with screen: FooScreen) {
view.backgroundColor = screen.backgroundColor
titleLabel.text = screen.title
}
+
+ @objc
+ private func viewTapped() {
+ screen.viewTapped()
+ }
}

MODIFY
swift/Samples/SplitScreenContainer/Sources/SplitScreenContainerScreen.swift
swift/Samples/SplitScreenContainer/Sources/SplitScreenContainerScreen.swift
@@ -17,32 +17,32 @@ import WorkflowUI
/// A `SplitScreenContainerScreen` displays two screens side by side with a separator in between.
-public struct SplitScreenContainerScreen<LeftScreenType: Screen, RightScreenType: Screen>: Screen {
+public struct SplitScreenContainerScreen<LeadingScreenType: Screen, TrailingScreenType: Screen>: Screen {
- /// The screen displayed to the left of the separator.
- public let leftScreen: LeftScreenType
+ /// The screen displayed leading the separator.
+ public let leadingScreen: LeadingScreenType
- /// The screen displayed to the right of the separator.
- public let rightScreen: RightScreenType
+ /// The screen displayed trailing the separator.
+ public let trailingScreen: TrailingScreenType
- /// The ratio of `leftScreen`'s width relative to that of `rightScreen`. Defaults to `.third`.
+ /// The ratio of `leadingScreen`'s width relative to that of `trailingScreen`. Defaults to `.third`.
public let ratio: CGFloat
- /// The color of the `separatorView` displayed between `leftScreen`'s and `rightScreen`'s views.
+ /// The color of the `separatorView` displayed between `leadingScreen`'s and `trailingScreen`'s views.
public let separatorColor: UIColor
- /// The width of the `separatorView` displayed between `leftScreen`'s and `rightScreen`'s views.
+ /// The width of the `separatorView` displayed between `leadingScreen`'s and `trailingScreen`'s views.
public let separatorWidth: CGFloat
public init(
- leftScreen: LeftScreenType,
- rightScreen: RightScreenType,
+ leadingScreen: LeadingScreenType,
+ trailingScreen: TrailingScreenType,
ratio: CGFloat = .third,
separatorColor: UIColor = .black,
separatorWidth: CGFloat = 1.0
) {
- self.leftScreen = leftScreen
- self.rightScreen = rightScreen
+ self.leadingScreen = leadingScreen
+ self.trailingScreen = trailingScreen
self.ratio = ratio
self.separatorColor = separatorColor
self.separatorWidth = separatorWidth

MODIFY
swift/Samples/SplitScreenContainer/Sources/SplitScreenContainerViewController.swift
swift/Samples/SplitScreenContainer/Sources/SplitScreenContainerViewController.swift
import Workflow
import WorkflowUI
-public final class SplitScreenContainerViewController<LeftScreenType: Screen, RightScreenType: Screen>: ScreenViewController<SplitScreenContainerViewController.ContainerScreen> {
- public typealias ContainerScreen = SplitScreenContainerScreen<LeftScreenType, RightScreenType>
+public final class SplitScreenContainerViewController<LeadingScreenType: Screen, TrailingScreenType: Screen>: ScreenViewController<SplitScreenContainerViewController.ContainerScreen> {
+ public typealias ContainerScreen = SplitScreenContainerScreen<LeadingScreenType, TrailingScreenType>
- private var leftContentViewController: ScreenViewController<LeftScreenType>? = nil
- private lazy var leftContainerView: UIView = .init()
+ private var leadingContentViewController: ScreenViewController<LeadingScreenType>? = nil
+ private lazy var leadingContainerView: UIView = .init()
private lazy var separatorView: UIView = .init()
- private var rightContentViewController: ScreenViewController<RightScreenType>? = nil
- private lazy var rightContainerView: UIView = .init()
+ private var trailingContentViewController: ScreenViewController<TrailingScreenType>? = nil
+ private lazy var trailingContainerView: UIView = .init()
private var currentRatio: CGFloat {
didSet {
@@ -63,8 +63,8 @@ public final class SplitScreenContainerViewController<LeftScreenType: Screen, Ri
private func update(with screen: ContainerScreen) {
separatorView.backgroundColor = screen.separatorColor
- leftContentViewController?.update(screen: screen.leftScreen)
- rightContentViewController?.update(screen: screen.rightScreen)
+ leadingContentViewController?.update(screen: screen.leadingScreen)
+ trailingContentViewController?.update(screen: screen.trailingScreen)
//Intentional force of layout pass after updating the child view controllers
view.layoutIfNeeded()
@@ -85,12 +85,12 @@ public final class SplitScreenContainerViewController<LeftScreenType: Screen, Ri
override public func viewDidLoad() {
super.viewDidLoad()
- view.addSubview(leftContainerView)
+ view.addSubview(leadingContainerView)
view.addSubview(separatorView)
- view.addSubview(rightContainerView)
+ view.addSubview(trailingContainerView)
- self.leftContentViewController = embed(screen.leftScreen, in: leftContainerView)
- self.rightContentViewController = embed(screen.rightScreen, in: rightContainerView)
+ self.leadingContentViewController = embed(screen.leadingScreen, in: leadingContainerView)
+ self.trailingContentViewController = embed(screen.trailingScreen, in: trailingContainerView)
update(with: screen)
}
@@ -99,15 +99,27 @@ public final class SplitScreenContainerViewController<LeftScreenType: Screen, Ri
let distance = view.bounds.width * currentRatio
- let (firstSlice, rightRect) = view.bounds.divided(atDistance: distance, from: .minXEdge)
+ let (firstSlice, trailingRect) = view.bounds.divided(atDistance: distance, from: .minXEdge)
- let (leftRect, separatorRect) = firstSlice.divided(atDistance: distance - currentSeparatorWidth, from: .minXEdge)
+ let (leadingRect, separatorRect) = firstSlice.divided(atDistance: distance - currentSeparatorWidth, from: .minXEdge)
+
+ let isRightToLeft = isLayoutDirectionRightToLeft()
+
+ leadingContainerView.frame = isRightToLeft ? trailingRect: leadingRect
+ leadingContentViewController?.view.frame = leadingContainerView.bounds
- leftContainerView.frame = leftRect
separatorView.frame = separatorRect
- rightContainerView.frame = rightRect
- leftContentViewController?.view.frame = leftRect
- rightContentViewController?.view.frame = CGRect(x: 0, y: 0, width: rightRect.width, height: rightRect.height)
+
+ trailingContainerView.frame = isRightToLeft ? leadingRect : trailingRect
+ trailingContentViewController?.view.frame = trailingContainerView.bounds
+ }
+
+ private func isLayoutDirectionRightToLeft() -> Bool {
+ if #available(iOS 10.0, *) {
+ return traitCollection.layoutDirection == .rightToLeft
+ } else {
+ return UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) == .rightToLeft
+ }
}
private func embed<ScreenType: Screen>(_ screen: ScreenType, in containerView: UIView) -> ScreenViewController<ScreenType> {

Rename `left` and `right` to `leading` and `trailing` and respect layout direction.