Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full screen portal #81

Merged
merged 18 commits into from Sep 10, 2019
Expand Up @@ -6,6 +6,11 @@ import android.view.ViewGroup
import com.badoo.ribs.android.ActivityStarter
import com.badoo.ribs.android.PermissionRequester
import com.badoo.ribs.android.RibActivity
import com.badoo.ribs.core.routing.action.AttachRibRoutingAction.Companion.attach
import com.badoo.ribs.core.routing.action.RoutingAction
import com.badoo.ribs.core.routing.portal.Portal
import com.badoo.ribs.core.routing.portal.PortalBuilder
import com.badoo.ribs.core.routing.portal.PortalNode
import com.badoo.ribs.customisation.RibCustomisationDirectory
import com.badoo.ribs.dialog.DialogLauncher
import com.badoo.ribs.example.R
Expand All @@ -16,6 +21,7 @@ import com.badoo.ribs.example.rib.switcher.builder.SwitcherBuilder
import com.badoo.ribs.example.util.CoffeeMachine
import com.badoo.ribs.example.util.StupidCoffeeMachine
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.functions.BiFunction

/** The sample app's single activity */
Expand All @@ -29,16 +35,31 @@ class RootActivity : RibActivity() {
override val rootViewGroup: ViewGroup
get() = findViewById(R.id.root)

private lateinit var workflowRoot: Switcher.Workflow
private lateinit var workflowRoot: Portal.Workflow

override fun createRib(savedInstanceState: Bundle?): SwitcherNode =
SwitcherBuilder(
object : Switcher.Dependency {
override fun ribCustomisation(): RibCustomisationDirectory = AppRibCustomisations
override fun activityStarter(): ActivityStarter = activityStarter
override fun permissionRequester(): PermissionRequester = permissionRequester
override fun dialogLauncher(): DialogLauncher = this@RootActivity
override fun coffeeMachine(): CoffeeMachine = StupidCoffeeMachine()
override fun createRib(savedInstanceState: Bundle?): PortalNode =
PortalBuilder(
object : Portal.Dependency {
override fun defaultRoutingAction(): (Portal.OtherSide) -> RoutingAction<Nothing> = { portal ->
attach { buildSwitcherNode(portal, it) }
}

private fun buildSwitcherNode(portal: Portal.OtherSide, savedInstanceState: Bundle?): SwitcherNode {
return SwitcherBuilder(
object : Switcher.Dependency {
override fun ribCustomisation(): RibCustomisationDirectory =
AppRibCustomisations

override fun activityStarter(): ActivityStarter = activityStarter
override fun permissionRequester(): PermissionRequester =
permissionRequester

override fun dialogLauncher(): DialogLauncher = this@RootActivity
override fun coffeeMachine(): CoffeeMachine = StupidCoffeeMachine()
override fun portal(): Portal.OtherSide = portal
}
).build(savedInstanceState)
}
}
).build(savedInstanceState).also {
workflowRoot = it
Expand All @@ -59,27 +80,33 @@ class RootActivity : RibActivity() {
}

private fun executeWorkflow1(): Observable<*> =
workflowRoot
.attachHelloWorld()
switcher()
.flatMap { it.attachHelloWorld()}
.toObservable()

@SuppressWarnings("OptionalUnit")
private fun executeWorkflow2(): Observable<*> =
Observable.combineLatest(
workflowRoot
.doSomethingAndStayOnThisNode()
switcher()
.flatMap { it.doSomethingAndStayOnThisNode() }
.toObservable(),

workflowRoot
.waitForHelloWorld()
switcher()
.flatMap { it.waitForHelloWorld() }
.flatMap { it.somethingSomethingDarkSide() }
.toObservable(),

BiFunction<Switcher.Workflow, HelloWorld.Workflow, Unit> { _, _ -> Unit }
)

private fun executeTestCrash(): Observable<*> =
(rootNode as Switcher.Workflow)
.testCrash()
switcher()
.flatMap { it.testCrash() }
.toObservable()

@Suppress("UNCHECKED_CAST")
private fun switcher() =
Single
.just(workflowRoot)
.flatMap { it.showDefault() as Single<Switcher.Workflow> }
}
@@ -0,0 +1,19 @@
package com.badoo.ribs.example.rib.big

import com.badoo.ribs.core.Rib
import com.badoo.ribs.customisation.CanProvidePortal
import com.badoo.ribs.customisation.CanProvideRibCustomisation
import com.badoo.ribs.customisation.RibCustomisation

interface Big : Rib {

interface Dependency :
CanProvideRibCustomisation,
CanProvidePortal

class Customisation(
val viewFactory: BigView.Factory = BigViewImpl.Factory()
) : RibCustomisation

interface Workflow
}
@@ -0,0 +1,23 @@
package com.badoo.ribs.example.rib.big

import android.arch.lifecycle.Lifecycle
import android.os.Bundle
import com.badoo.ribs.core.Interactor
import com.badoo.ribs.core.Router
import com.badoo.ribs.example.rib.big.BigRouter.Configuration
import com.badoo.ribs.example.rib.big.BigRouter.Configuration.Content
import com.badoo.ribs.example.rib.big.BigRouter.Configuration.Overlay

class BigInteractor(
savedInstanceState: Bundle?,
router: Router<Configuration, *, Content, Overlay, BigView>
) : Interactor<Configuration, Content, Overlay, BigView>(
savedInstanceState = savedInstanceState,
router = router,
disposables = null
) {

override fun onViewCreated(view: BigView, viewLifecycle: Lifecycle) {
view.accept(BigView.ViewModel("My id: " + id.replace("${BigInteractor::class.java.name}.", "")))
}
}
@@ -0,0 +1,18 @@
package com.badoo.ribs.example.rib.big

import android.os.Bundle
import android.view.ViewGroup
import com.badoo.ribs.core.Node

class BigNode(
savedInstanceState: Bundle?,
viewFactory: ((ViewGroup) -> BigView?)?,
private val router: BigRouter,
private val interactor: BigInteractor
) : Node<BigView>(
savedInstanceState = savedInstanceState,
identifier = object : Big {},
viewFactory = viewFactory,
router = router,
interactor = interactor
), Big.Workflow
@@ -0,0 +1,39 @@
package com.badoo.ribs.example.rib.big

import android.os.Bundle
import android.os.Parcelable
import com.badoo.ribs.core.Router
import com.badoo.ribs.core.routing.action.AttachRibRoutingAction.Companion.attach
import com.badoo.ribs.core.routing.action.RoutingAction
import com.badoo.ribs.core.routing.action.RoutingAction.Companion.noop
import com.badoo.ribs.example.rib.big.BigRouter.Configuration
import com.badoo.ribs.example.rib.big.BigRouter.Configuration.Content
import com.badoo.ribs.example.rib.big.BigRouter.Configuration.Overlay
import com.badoo.ribs.example.rib.big.BigRouter.Configuration.Permanent
import com.badoo.ribs.example.rib.small.builder.SmallBuilder
import kotlinx.android.parcel.Parcelize

class BigRouter(
savedInstanceState: Bundle?,
private val smallBuilder: SmallBuilder
): Router<Configuration, Permanent, Content, Overlay, BigView>(
savedInstanceState = savedInstanceState,
initialConfiguration = Content.Default,
permanentParts = listOf(Permanent.Small)
) {
sealed class Configuration : Parcelable {
sealed class Permanent : Configuration() {
@Parcelize object Small : Permanent()
}
sealed class Content : Configuration() {
@Parcelize object Default : Content()
}
sealed class Overlay : Configuration()
}

override fun resolveConfiguration(configuration: Configuration): RoutingAction<BigView> =
when (configuration) {
Permanent.Small -> attach { smallBuilder.build(it) }
Content.Default -> noop()
}
}
@@ -0,0 +1,61 @@
package com.badoo.ribs.example.rib.big

import android.support.annotation.LayoutRes
import android.view.ViewGroup
import android.widget.TextView
import com.badoo.ribs.core.Rib
import com.badoo.ribs.core.view.RibView
import com.badoo.ribs.core.view.ViewFactory
import com.badoo.ribs.customisation.inflate
import com.badoo.ribs.example.R
import com.badoo.ribs.example.rib.big.BigView.Event
import com.badoo.ribs.example.rib.big.BigView.ViewModel
import com.badoo.ribs.example.rib.small.Small
import com.jakewharton.rxrelay2.PublishRelay
import io.reactivex.ObservableSource
import io.reactivex.functions.Consumer

interface BigView : RibView,
ObservableSource<Event>,
Consumer<ViewModel> {

sealed class Event

data class ViewModel(
val text: String
)

interface Factory : ViewFactory<Nothing?, BigView>
}


class BigViewImpl private constructor(
override val androidView: ViewGroup,
private val events: PublishRelay<Event> = PublishRelay.create()
) : BigView,
ObservableSource<Event> by events,
Consumer<ViewModel> {

class Factory(
@LayoutRes private val layoutRes: Int = R.layout.rib_big
) : BigView.Factory {
override fun invoke(deps: Nothing?): (ViewGroup) -> BigView = {
BigViewImpl(
inflate(it, layoutRes)
)
}
}

private val idText = androidView.findViewById<TextView>(R.id.big_id)
private val smallContainer = androidView.findViewById<ViewGroup>(R.id.small_container)

override fun accept(vm: ViewModel) {
idText.text = vm.text
}

override fun getParentViewForChild(child: Rib): ViewGroup? =
when (child) {
is Small -> smallContainer
else -> null
}
}
@@ -0,0 +1,27 @@
package com.badoo.ribs.example.rib.big.builder

import android.os.Bundle
import com.badoo.ribs.core.Builder
import com.badoo.ribs.customisation.customisationsBranchFor
import com.badoo.ribs.customisation.getOrDefault
import com.badoo.ribs.example.rib.big.Big
import com.badoo.ribs.example.rib.big.BigNode

class BigBuilder(
dependency: Big.Dependency
) : Builder<Big.Dependency>() {

override val dependency : Big.Dependency = object : Big.Dependency by dependency {
override fun ribCustomisation() = dependency.customisationsBranchFor(Big::class)
}

fun build(savedInstanceState: Bundle?): BigNode =
DaggerBigComponent
.factory()
.create(
dependency = dependency,
customisation = dependency.getOrDefault(Big.Customisation()),
savedInstanceState = savedInstanceState
)
.node()
}
@@ -0,0 +1,26 @@
package com.badoo.ribs.example.rib.big.builder

import android.os.Bundle
import com.badoo.ribs.example.rib.big.Big
import com.badoo.ribs.example.rib.big.BigNode
import com.badoo.ribs.example.rib.small.Small
import dagger.BindsInstance

@BigScope
@dagger.Component(
modules = [BigModule::class],
dependencies = [Big.Dependency::class]
)
internal interface BigComponent : Small.Dependency {

@dagger.Component.Factory
interface Factory {
fun create(
dependency: Big.Dependency,
@BindsInstance customisation: Big.Customisation,
@BindsInstance savedInstanceState: Bundle?
): BigComponent
}

fun node(): BigNode
}
@@ -0,0 +1,54 @@
@file:SuppressWarnings("LongParameterList", "LongMethod")
package com.badoo.ribs.example.rib.big.builder

import android.os.Bundle
import com.badoo.ribs.example.rib.big.Big
import com.badoo.ribs.example.rib.big.BigInteractor
import com.badoo.ribs.example.rib.big.BigNode
import com.badoo.ribs.example.rib.big.BigRouter
import com.badoo.ribs.example.rib.small.builder.SmallBuilder
import dagger.Provides

@dagger.Module
internal object BigModule {

@BigScope
@Provides
@JvmStatic
internal fun router(
// pass component to child rib builders, or remove if there are none
component: BigComponent,
savedInstanceState: Bundle?
): BigRouter =
BigRouter(
savedInstanceState = savedInstanceState,
smallBuilder = SmallBuilder(component)
)

@BigScope
@Provides
@JvmStatic
internal fun interactor(
savedInstanceState: Bundle?,
router: BigRouter
): BigInteractor =
BigInteractor(
savedInstanceState = savedInstanceState,
router = router
)

@BigScope
@Provides
@JvmStatic
internal fun node(
savedInstanceState: Bundle?,
customisation: Big.Customisation,
router: BigRouter,
interactor: BigInteractor
) : BigNode = BigNode(
savedInstanceState = savedInstanceState,
viewFactory = customisation.viewFactory(null),
router = router,
interactor = interactor
)
}
@@ -0,0 +1,7 @@
package com.badoo.ribs.example.rib.big.builder

import javax.inject.Scope

@Scope
@Retention(AnnotationRetention.RUNTIME)
zsoltk marked this conversation as resolved.
Show resolved Hide resolved
zsoltk marked this conversation as resolved.
Show resolved Hide resolved
internal annotation class BigScope