Skip to content

Commit

Permalink
Merge pull request #1 from theshiftstudio/tudor/account-flow
Browse files Browse the repository at this point in the history
Having fun with FirebaseAuthUI, Workflows & Compose. YAY!
  • Loading branch information
lucamtudor authored Sep 2, 2021
2 parents 65d4994 + e3266fd commit 100cd01
Show file tree
Hide file tree
Showing 31 changed files with 1,032 additions and 71 deletions.
17 changes: 16 additions & 1 deletion .idea/inspectionProfiles/ktlint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ plugins {
kotlin("plugin.serialization")

id("dagger.hilt.android.plugin")

// id("com.google.gms.google-services")
}

android {
Expand Down Expand Up @@ -105,8 +107,6 @@ dependencies {

implementation(COIL.compose)

// implementation("com.squareup.workflow1:workflow-ui-core-android:_")
// implementation(Dependencies.Square.Workflow.uiCoreAndroid)
implementation(Dependencies.Square.Workflow.compose)
implementation(Dependencies.Square.Workflow.composeTooling)

Expand All @@ -115,6 +115,10 @@ dependencies {
implementation(AndroidX.lifecycle.viewModelCompose)
implementation(AndroidX.lifecycle.viewModelSavedState)

implementation(platform(Firebase.bom))
implementation(Firebase.authenticationKtx)
implementation(Dependencies.Firebase.uiAuth)

debugImplementation(Square.leakCanary.android)

testImplementation(Testing.junit4)
Expand Down
8 changes: 6 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
package="com.shiftstudio.workflowshenanigans">

<application
android:allowBackup="true"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:name=".infrastructure.ShenanigansApplication"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.WorkflowShenanigans">

<activity
android:name=".MainActivity"
android:name=".infrastructure.MainActivity"
android:configChanges="colorMode|density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.WorkflowShenanigans.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.shiftstudio.workflowshenanigans

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
abstract class ShenanigansModule {

@Binds
abstract fun bindShenanigansWorkflow(impl: ShenanigansWorkflowImpl): ShenanigansWorkflow
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
@file:OptIn(WorkflowUiExperimentalApi::class)

package com.shiftstudio.workflowshenanigans

import androidx.activity.ComponentActivity
import com.shiftstudio.workflowshenanigans.ShenanigansWorkflow.ActivityAndProps
import com.shiftstudio.workflowshenanigans.account.AccountViewRegistry
import com.shiftstudio.workflowshenanigans.account.AccountWorkflow
import com.shiftstudio.workflowshenanigans.login.LoginViewRegistry
import com.shiftstudio.workflowshenanigans.welcome.WelcomeWorkflow
import com.squareup.workflow1.Snapshot
import com.squareup.workflow1.StatefulWorkflow
import com.squareup.workflow1.Workflow
import com.squareup.workflow1.action
import com.squareup.workflow1.parse
import com.squareup.workflow1.ui.NamedViewFactory
import com.squareup.workflow1.ui.ViewRegistry
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.backstack.BackStackContainer
import com.squareup.workflow1.ui.backstack.BackStackScreen
import com.squareup.workflow1.ui.backstack.toBackStackScreen
import com.squareup.workflow1.ui.plus
import javax.inject.Inject

interface ShenanigansWorkflow : Workflow<ActivityAndProps<Unit>, Nothing, BackStackScreen<Any>> {

data class ActivityAndProps<R>(
val activity: ComponentActivity,
val props: R
)
}

val ShenanigansViewRegistry: ViewRegistry = ViewRegistry(BackStackContainer, NamedViewFactory) +
AccountViewRegistry +
LoginViewRegistry

class ShenanigansWorkflowImpl @Inject constructor(
private val welcomeWorkflow: WelcomeWorkflow,
private val accountWorkflow: AccountWorkflow,
) : ShenanigansWorkflow,
StatefulWorkflow<ActivityAndProps<Unit>, ShenanigansWorkflowImpl.State, Nothing, BackStackScreen<Any>>() {

sealed class State {
object Welcome : State()

object Account : State()
}

override fun initialState(props: ActivityAndProps<Unit>, snapshot: Snapshot?): State {
return snapshot?.bytes
?.parse { source -> if (source.readInt() == 0) State.Welcome else State.Account }
?: State.Welcome
}

override fun render(
renderProps: ActivityAndProps<Unit>,
renderState: State,
context: RenderContext
): BackStackScreen<Any> {
val backStack = mutableListOf<Any>()

val welcomeScreen = context.renderChild(welcomeWorkflow, Unit) { output ->
handleWelcomeOutput(output)
}
backStack += welcomeScreen

when (renderState) {
is State.Welcome -> {
// We always add the welcome screen to the backstack, so this is a no op.
}
is State.Account -> {
val accountScreen = context.renderChild(accountWorkflow, renderProps) {
goToWelcome()
}
backStack += accountScreen
}
}

return backStack.toBackStackScreen()
}

private fun handleWelcomeOutput(output: WelcomeWorkflow.Output) = action {
when (output) {
is WelcomeWorkflow.Output.GoToAccount -> {
state = State.Account
}
}
}

private fun goToWelcome() = action {
state = State.Welcome
}

override fun snapshotState(state: State): Snapshot {
return Snapshot.of(if (state == State.Welcome) 0 else 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.shiftstudio.workflowshenanigans.account

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
abstract class AccountModule {

@Binds
abstract fun bindAccountWorkflow(impl: AccountWorkflowImpl): AccountWorkflow
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@file:OptIn(WorkflowUiExperimentalApi::class)

package com.shiftstudio.workflowshenanigans.account

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.squareup.workflow1.ui.ViewRegistry
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.compose.composeViewFactory

private val LoadingUserBinding = composeViewFactory<LoadingUserRendering> { _, _ ->
Surface(color = MaterialTheme.colors.background) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}
}

private val UserRenderingBinding = composeViewFactory<UserRendering> { rendering, _ ->
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = rendering.user.name)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { rendering.onSignOut() }) {
Text(text = "Sign out")
}
}
}

val AccountViewRegistry = ViewRegistry(LoadingUserBinding, UserRenderingBinding)
Loading

0 comments on commit 100cd01

Please sign in to comment.