Skip to content

Commit

Permalink
replace callbacks in Rendering with an action sink
Browse files Browse the repository at this point in the history
  • Loading branch information
square-tomb committed Jun 22, 2023
1 parent 2fbfc5e commit d3fb358
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 37 deletions.
1 change: 1 addition & 0 deletions Development.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Pod::Spec.new do |s|
test_spec.dependency 'BackStackContainer'
test_spec.dependency 'ModalContainer'
test_spec.dependency 'AlertContainer'
test_spec.dependency 'WorkflowSwiftUI'
test_spec.requires_app_host = true
test_spec.app_host_name = 'Development/SampleTicTacToe'
test_spec.source_files = 'Samples/TicTacToe/Tests/**/*.swift'
Expand Down
14 changes: 6 additions & 8 deletions Samples/TicTacToe/Sources/Authentication/LoginScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
import SwiftUI
import WorkflowSwiftUI

struct LoginScreen: SwiftUIScreen {
struct LoginScreen: SwiftUIScreen, Equatable {
var actionSink: ScreenActionSink<LoginWorkflow.Action>
var title: String
var email: String
var onEmailChanged: (String) -> Void
var password: String
var onPasswordChanged: (String) -> Void
var onLoginTapped: () -> Void

static func makeView(model: ObservableValue<LoginScreen>) -> some View {
VStack(spacing: 16) {
Expand All @@ -33,7 +31,7 @@ struct LoginScreen: SwiftUIScreen {
"[email protected]",
text: model.binding(
get: \.email,
set: \.onEmailChanged
set: { screen in { screen.actionSink.send(.emailUpdated($0)) } }
)
)
.autocapitalization(.none)
Expand All @@ -44,12 +42,12 @@ struct LoginScreen: SwiftUIScreen {
"password",
text: model.binding(
get: \.password,
set: \.onPasswordChanged
set: { screen in { screen.actionSink.send(.passwordUpdated($0)) } }
),
onCommit: model.onLoginTapped
onCommit: { model.value.actionSink.send(.login) }
)

Button("Login", action: model.onLoginTapped)
Button("Login", action: { model.value.actionSink.send(.login) })
}
.frame(maxWidth: 400)
}
Expand Down
16 changes: 3 additions & 13 deletions Samples/TicTacToe/Sources/Authentication/LoginWorkflow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,11 @@ extension LoginWorkflow {
typealias Rendering = LoginScreen

func render(state: LoginWorkflow.State, context: RenderContext<LoginWorkflow>) -> Rendering {
let sink = context.makeSink(of: Action.self)

return LoginScreen(
LoginScreen(
actionSink: .init(context.makeSink(of: Action.self)),
title: "Welcome! Please log in to play TicTacToe!",
email: state.email,
onEmailChanged: { email in
sink.send(.emailUpdated(email))
},
password: state.password,
onPasswordChanged: { password in
sink.send(.passwordUpdated(password))
},
onLoginTapped: {
sink.send(.login)
}
password: state.password
)
}
}
24 changes: 8 additions & 16 deletions Samples/TicTacToe/Tests/AuthenticationWorkflowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,10 @@ class AuthenticationWorkflowTests: XCTestCase {
.expectWorkflow(
type: LoginWorkflow.self,
producingRendering: LoginScreen(
actionSink: .noop(),
title: "",
email: "",
onEmailChanged: { _ in },
password: "",
onPasswordChanged: { _ in },
onLoginTapped: {}
password: ""
)
)
.render { screen in
Expand All @@ -210,12 +208,10 @@ class AuthenticationWorkflowTests: XCTestCase {
.expectWorkflow(
type: LoginWorkflow.self,
producingRendering: LoginScreen(
actionSink: .noop(),
title: "",
email: "",
onEmailChanged: { _ in },
password: "",
onPasswordChanged: { _ in },
onLoginTapped: {}
password: ""
)
)
.expect(
Expand Down Expand Up @@ -244,12 +240,10 @@ class AuthenticationWorkflowTests: XCTestCase {
.expectWorkflow(
type: LoginWorkflow.self,
producingRendering: LoginScreen(
actionSink: .noop(),
title: "",
email: "",
onEmailChanged: { _ in },
password: "",
onPasswordChanged: { _ in },
onLoginTapped: {}
password: ""
)
)
.expect(
Expand All @@ -275,12 +269,10 @@ class AuthenticationWorkflowTests: XCTestCase {
.expectWorkflow(
type: LoginWorkflow.self,
producingRendering: LoginScreen(
actionSink: .noop(),
title: "",
email: "",
onEmailChanged: { _ in },
password: "",
onPasswordChanged: { _ in },
onLoginTapped: {}
password: ""
)
)
.render { screen in
Expand Down
38 changes: 38 additions & 0 deletions WorkflowSwiftUI/Sources/ScreenActionSink.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2023 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 Workflow

public struct ScreenActionSink<Value>: Equatable {
private let sink: Sink<Value>

// TODO: Only allow this to be initialized by `WorkflowNode.SubtreeManager.Context`?
public init(_ sink: Sink<Value>) {
self.sink = sink
}

public static func noop<T>() -> ScreenActionSink<T> {
ScreenActionSink<T>(Sink { _ in })
}

public func send(_ value: Value) {
sink.send(value)
}

public static func == (lhs: ScreenActionSink<Value>, rhs: ScreenActionSink<Value>) -> Bool {
true
}
}
3 changes: 3 additions & 0 deletions WorkflowSwiftUI/Sources/SwiftUIScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import WorkflowUI

public protocol SwiftUIScreen: Screen {
associatedtype Content: View
associatedtype Action

@ViewBuilder
static func makeView(model: ObservableValue<Self>) -> Content

var actionSink: ScreenActionSink<Action> { get }

static var isDuplicate: ((Self, Self) -> Bool)? { get }
}

Expand Down

0 comments on commit d3fb358

Please sign in to comment.