Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Using Square Workflow for Android & iOS
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Mohit S
May 18, 2022
Programming
560
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Using Square Workflow for Android & iOS
Mohit S
May 18, 2022
More Decks by Mohit S
See All by Mohit S
Guide to Improving Compose Performance
heyitsmohit
0
360
Building Shared UIs across Platforms with Compose
heyitsmohit
1
750
Building Multiplatform Apps with Compose
heyitsmohit
2
660
Building StateFlows with Jetpack Compose
heyitsmohit
6
2.1k
Building Android Testing Infrastructure
heyitsmohit
1
670
Migrating to Kotlin State & Shared Flows
heyitsmohit
1
920
Building Android Infrastructure Teams at Scale
heyitsmohit
3
450
Strategies for Migrating to Jetpack Compose
heyitsmohit
2
700
Challenges of Building Kotlin Multiplatform Libraries
heyitsmohit
1
550
Other Decks in Programming
See All in Programming
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
120
現場と育てるRailsモデリング 〜Spreadsheetから始めたモデル設計〜
siroemk
2
650
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
280
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
golang-bob.pdf
iwatsukayura
0
130
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
170
Performance Optimization With LLMs
xleitix
0
160
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
1k
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.7k
ActionController meets Protocol Buffers
sorah
0
570
Vue Fes Japan の “作る側”に関わってみて
naokihaba
0
160
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
300
Featured
See All Featured
Believing is Seeing
oripsolob
1
250
Code Review Best Practice
trishagee
74
20k
Writing Fast Ruby
sferik
630
63k
Optimizing for Happiness
mojombo
378
71k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
2
360
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.3k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
2
410
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
430
Transcript
Mohit Sarveiya Using Square Workflow for Android & iOS @heyitsmohit
Using Square Workflow for Android & iOS • Purpose •
Building screens & setting up state • Working with Compose
Purpose • Clear boundaries between components • Immutable State •
Separation between state & UI
Workflow
Workflow (State)
Workflow (State) Actions
Workflow (State) Actions
Workflow (State) Rendering
Action UI
Action UI State
Action UI State Rendering
Action UI State Rendering
Creating Workflows • State • Actions • Screens
Square Workflow with Android Screens, Workflows & Renderings
9:41 Login Username Password
Workflow Layout Runner Screen
Setup • AndroidX View Model • View Binding
Screen • Represents view model for screen
Screen data class LoginScreen( val username: String, Val password: String,
val onLoginClicked: () -> Unit )
Layout Runner • Specifies how to update views • Supports
view binding
Layout Runner class LoginLayoutRunner( val loginViewBinding: LoginViewBinding ) : LayoutRunner<LoginScreen>
{ }
Layout Runner override fun showRendering(rendering: LoginScreen) { loginViewBinding.username.text = rendering.username
loginViewBinding.username.setTextChangedListener { rendering.onUsernameChanged(it.toString()) } loginViewBinding.login.setOnClickListener { rendering.onLoginClicked() } }
Layout Runner override fun showRendering(rendering: LoginScreen) { loginViewBinding.username.text = rendering.username
loginViewBinding.username.setTextChangedListener { rendering.onUsernameChanged(it.toString()) } loginViewBinding.login.setOnClickListener { rendering.onLoginClicked() } }
Layout Runner override fun showRendering(rendering: LoginScreen) { loginViewBinding.username.text = rendering.username
loginViewBinding.username.setTextChangedListener { rendering.onUsernameChanged(it.toString()) } loginViewBinding.login.setOnClickListener { rendering.onLoginClicked() } }
Layout Runner override fun showRendering(rendering: LoginScreen) { loginViewBinding.username.text = rendering.username
loginViewBinding.username.setTextChangedListener { rendering.onUsernameChanged(it.toString()) } loginViewBinding.login.setOnClickListener { rendering.onLoginClicked() } }
Workflow Layout Runner Screen
Workflow (State) Rendering Actions
data class State( val username: String, val password: String )
State
fun onUsernameChanged(username: String) = action { state = state.copy(username =
username) } Action
object LoginWorkflow : StatefulWorkflow<State, LoginScreen> { } Workflow
object LoginWorkflow : StatefulWorkflow<State, LoginScreen> { override fun initialState() {
} override fun render() { } } Workflow
object LoginWorkflow : StatefulWorkflow<State, LoginScreen> { override fun initialState() {
} override fun render() { } } Workflow
fun render(renderState: State) { } Workflow
fun render(renderState: State): LoginScreen { } Workflow
fun render(renderState: State): LoginScreen { LoginScreen( username = renderState.username, onUsernameChanged
= { ... }, onLoginCliked = {} ) } Workflow
fun render(renderState: State): LoginScreen { LoginScreen( username = renderState.username, onUsernameChanged
= { ... }, onLoginCliked = {} ) } Workflow
fun onUsernameChanged(username: String) = action { state = state.copy(username =
username) } Action
fun render(renderState: State): LoginScreen { LoginScreen( username = renderState.username, onUsernameChanged
= { context.actionSink.send() }, onLoginCliked = {} ) } Workflow
fun render(renderState: State): LoginScreen { LoginScreen( username = renderState.username, onUsernameChanged
= { context.actionSink.send(onUserChanged(it)) }, onLoginCliked = {} ) } Workflow
fun initialState(): State { State( username = "" ) }
Workflow
Workflow (State) Rendering Actions
View & View Model View View Model Workflow
View Model class LoginViewModel : ViewModel() { val renderings: StateFlow<LoginScreen>
by lazy { renderWorkflowIn( workflow = LoginWorkflow, scope = viewModelScope, savedStateHandle = savedState ) } }
View Model class LoginViewModel : ViewModel() { val renderings: StateFlow<LoginScreen>
by lazy { renderWorkflowIn( workflow = LoginWorkflow, scope = viewModelScope, savedStateHandle = savedState ) } }
View class LoginActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) val model: LoginViewModel by viewModels() setContentView( WorkflowLayout(this).apply { start(model.renderings) } ) } }
View class LoginActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) val model: LoginViewModel by viewModels() setContentView( WorkflowLayout(this).apply { start(model.renderings) } ) } }
View class LoginActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView( WorkflowLayout(this).apply { start(model.renderings) } ) } }
Workflow Layout Runner Screen
9:41 Login Username Password
Action UI State Rendering
Navigation & Props
Workflow B Workflow A Props
9:41 Login Username Password
9:41 Login Username Password 9:41 Username
Todo Workflow Login Workflow Root Workflow
Root Workflow • Navigation States • Backstack
sealed class State { object Login : State() } State
sealed class State { object Login : State() data class
Todo(val username: String) : State() } State
Root Workflow object RootWorkflow : StatefulWorkflow { }
Root Workflow object RootWorkflow : StatefulWorkflow { fun render( renderProps:
Unit, renderState: State, context: RenderContext ): BackStackScreen<Any> }
Root Workflow fun render( ... ): BackStackScreen<Any> { val
backstackScreens = mutableListOf<Any>() }
Root Workflow fun render( ... ): BackStackScreen<Any> { val
loginScreen = context.renderChild(LoginWorkflow) }
Root Workflow fun render( ... ): BackStackScreen<Any> { val
loginScreen = context.renderChild(LoginWorkflow) backstackScreens += loginScreen }
Root Workflow fun render( ... ): BackStackScreen<Any> { when
(renderState) { is Todo -> { } } }
Root Workflow fun render( ... ): BackStackScreen<Any> { when
(renderState) { is Todo -> { val todoScreen = context.renderChild(TodoWorkflow) backstackScreens += todoScreen } } }
Todo Workflow Login Workflow Root Workflow
Todo List Screen data class TodoListScreen( val username: String, val
todoTitles: List<String> )
Todo Workflow State data class State( val todos: List<TodoModel> )
Todo Workflow State fun initialState() = State( listOf( TodoModel( title
= "Workout", note = "Workout" ) ) )
Todo Workflow Login Workflow Props Username
Props object TodoListWorkflow : StatefulWorkflow() { data class ListProps(val username:
String) }
Todo Workflow Login Workflow Root Workflow
Root Workflow fun render( ... ): BackStackScreen<Any> { when (renderState)
{ is Todo -> { val todoScreen = context.renderChild(TodoWorkflow) backstackScreens += todoScreen } } }
Root Workflow fun render( ... ): BackStackScreen<Any> { when (renderState)
{ is Todo -> { val todoScreen = context.renderChild( TodoWorkflow, ListProps(username = renderState.username) ) } } }
View Model View
View Model class LoginViewModel : ViewModel() { val renderings: StateFlow<LoginScreen>
by lazy { renderWorkflowIn( workflow = LoginWorkflow, scope = viewModelScope, savedStateHandle = savedState ) } }
View Model class LoginViewModel : ViewModel() { val renderings: StateFlow<LoginScreen>
by lazy { renderWorkflowIn( workflow = RootWorkflow, scope = viewModelScope, savedStateHandle = savedState ) } }
Todo Layout Runner Login Layout Runner
View Registry val viewRegistry = ViewRegistry( BackStackContainer, LoginLayoutRunner, TodoListLayoutRunner )
View Registry setContentView( WorkflowLayout(this).apply { start(model.renderings, viewRegistry) } )
Todo Workflow Login Workflow Root Workflow
9:41 Login Username Password 9:41 Username
Square Workflow with Jetpack Compose
9:41 Hello 9:41 Goodbye
Workflow Binding
Rendering data class Rendering( val message: String, val onClick: ()
-> Unit )
Binding composeScreenViewFactory<HelloWorkflow.Rendering> { rendering, _ -> Text( rendering.message, modifier =
Modifier .clickable(onClick = rendering.onClick) .fillMaxSize() .wrapContentSize(Alignment.Center) ) }
Binding composeScreenViewFactory<HelloWorkflow.Rendering> { rendering, _ -> Text( rendering.message, modifier =
Modifier .clickable(onClick = rendering.onClick) .fillMaxSize() .wrapContentSize(Alignment.Center) ) }
State enum class State { Hello, Goodbye; fun theOtherState(): State
= when (this) { Hello -> Goodbye Goodbye -> Hello } }
Action val helloAction = action { state = state.theOtherState() }
Workflow object HelloWorkflow : StatefulWorkflow { }
Workflow object HelloWorkflow : StatefulWorkflow { override fun render():
Rendering = Rendering( message = renderState.name, onClick = { context.actionSink.send(helloAction) } ) }
Action UI State Rendering
9:41 Hello 9:41 Goodbye
None
None
Thank You! www.codingwithmohit.com @heyitsmohit