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
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
350
Building Shared UIs across Platforms with Compose
heyitsmohit
1
740
Building Multiplatform Apps with Compose
heyitsmohit
2
650
Building StateFlows with Jetpack Compose
heyitsmohit
6
2k
Building Android Testing Infrastructure
heyitsmohit
1
670
Migrating to Kotlin State & Shared Flows
heyitsmohit
1
910
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
540
Other Decks in Programming
See All in Programming
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
140
The Rails Doctrine Decade
koic
2
420
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
370
JRuby: Past, Present, and Future
headius
0
210
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
410
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
300
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
一人だけ、Kiroが静止する日
hideg
0
140
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
1
660
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
210
Workers Cache を知る
syumai
0
310
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
130
Featured
See All Featured
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
730
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
The agentic SEO stack - context over prompts
schlessera
0
940
Six Lessons from altMBA
skipperchong
29
4.5k
Utilizing Notion as your number one productivity tool
mfonobong
4
600
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
20k
The SEO Collaboration Effect
kristinabergwall1
1
580
Making the Leap to Tech Lead
cromwellryan
135
10k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Producing Creativity
orderedlist
PRO
348
41k
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