├── images ├── logo.png └── slack-logo-icon.png ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── scripts │ ├── detekt.yml │ ├── jacoco.gradle.kts │ ├── detekt.gradle.kts │ └── jacoco-android.gradle.kts ├── samples ├── orbit-2-posts │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── xml │ │ │ │ │ └── backup_descriptor.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── values │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── colors.xml │ │ │ │ │ ├── strings.xml │ │ │ │ │ ├── dimen.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── layout │ │ │ │ │ ├── post_list_fragment.xml │ │ │ │ │ └── main_activity.xml │ │ │ │ ├── drawable │ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ └── navigation │ │ │ │ │ └── nav_graph.xml │ │ │ ├── ic_launcher-web.png │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── babylon │ │ │ │ │ └── orbit2 │ │ │ │ │ └── sample │ │ │ │ │ └── posts │ │ │ │ │ ├── app │ │ │ │ │ ├── common │ │ │ │ │ │ └── NavigationEvent.kt │ │ │ │ │ ├── features │ │ │ │ │ │ ├── postlist │ │ │ │ │ │ │ └── viewmodel │ │ │ │ │ │ │ │ ├── OpenPostNavigationEvent.kt │ │ │ │ │ │ │ │ ├── PostListState.kt │ │ │ │ │ │ │ │ └── PostListViewModel.kt │ │ │ │ │ │ ├── postdetails │ │ │ │ │ │ │ ├── viewmodel │ │ │ │ │ │ │ │ ├── PostDetailState.kt │ │ │ │ │ │ │ │ └── PostDetailsViewModel.kt │ │ │ │ │ │ │ └── ui │ │ │ │ │ │ │ │ └── PostCommentItem.kt │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── PostsApplication.kt │ │ │ │ │ ├── data │ │ │ │ │ └── posts │ │ │ │ │ │ ├── model │ │ │ │ │ │ ├── PostData.kt │ │ │ │ │ │ ├── UserData.kt │ │ │ │ │ │ └── CommentData.kt │ │ │ │ │ │ └── network │ │ │ │ │ │ ├── AvatarUrlGenerator.kt │ │ │ │ │ │ └── TypicodeService.kt │ │ │ │ │ └── domain │ │ │ │ │ └── repositories │ │ │ │ │ ├── PostRepository.kt │ │ │ │ │ ├── Status.kt │ │ │ │ │ ├── PostDetail.kt │ │ │ │ │ ├── PostComment.kt │ │ │ │ │ └── PostOverview.kt │ │ │ └── AndroidManifest.xml │ │ └── test │ │ │ └── kotlin │ │ │ └── com │ │ │ └── babylon │ │ │ └── orbit2 │ │ │ └── sample │ │ │ └── posts │ │ │ ├── data │ │ │ └── posts │ │ │ │ └── network │ │ │ │ └── AvatarUrlGeneratorTest.kt │ │ │ └── InstantTaskExecutorExtension.kt │ ├── NOTICE.md │ ├── sampledata │ │ ├── comments.json │ │ └── posts.json │ └── README.md ├── orbit-2-stocklist │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── attrs.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable │ │ │ │ ├── tick.xml │ │ │ │ ├── arrow_up_bold.xml │ │ │ │ └── arrow_down_bold.xml │ │ │ ├── layout │ │ │ │ ├── list_fragment.xml │ │ │ │ └── main_activity.xml │ │ │ └── navigation │ │ │ │ └── nav_graph.xml │ │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── babylon │ │ │ │ └── orbit2 │ │ │ │ └── sample │ │ │ │ └── stocklist │ │ │ │ ├── list │ │ │ │ ├── business │ │ │ │ │ ├── ListSideEffect.kt │ │ │ │ │ ├── ListState.kt │ │ │ │ │ └── ListViewModel.kt │ │ │ │ └── ui │ │ │ │ │ └── TickAnimation.kt │ │ │ │ ├── detail │ │ │ │ └── business │ │ │ │ │ ├── DetailState.kt │ │ │ │ │ └── DetailViewModel.kt │ │ │ │ ├── streaming │ │ │ │ ├── stock │ │ │ │ │ ├── Stock.kt │ │ │ │ │ └── StockDetail.kt │ │ │ │ ├── EmptySubscriptionListener.kt │ │ │ │ └── StreamingClient.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── StockListApplication.kt │ │ │ └── AndroidManifest.xml │ ├── NOTICE.md │ └── README.md └── orbit-2-calculator │ ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── babylon │ │ │ │ └── orbit2 │ │ │ │ └── sample │ │ │ │ └── calculator │ │ │ │ ├── CalculatorState.kt │ │ │ │ ├── CalculatorActivity.kt │ │ │ │ └── CalculatorApplication.kt │ │ └── AndroidManifest.xml │ └── test │ │ └── kotlin │ │ └── com │ │ └── babylon │ │ └── orbit2 │ │ └── sample │ │ └── calculator │ │ └── livedata │ │ ├── MockLifecycleOwner.kt │ │ ├── InstantTaskExecutorExtension.kt │ │ └── TestLiveDataObserver.kt │ ├── NOTICE.md │ └── README.md ├── CHANGELOG.md ├── orbit-2-core ├── docs │ ├── orbit-2-overview-1.mmd │ ├── orbit-2-overview-2.mmd │ └── orbit-2-overview-3.mmd ├── src │ ├── main │ │ └── kotlin │ │ │ └── com │ │ │ └── babylon │ │ │ └── orbit2 │ │ │ ├── idling │ │ │ ├── IdlingResource.kt │ │ │ ├── NoopIdlingResource.kt │ │ │ ├── SimpleIdlingExtensions.kt │ │ │ └── OperatorIdlingExtensions.kt │ │ │ ├── syntax │ │ │ ├── strict │ │ │ │ ├── SideEffectContext.kt │ │ │ │ ├── StrictSyntax.kt │ │ │ │ ├── Context.kt │ │ │ │ ├── VolatileContext.kt │ │ │ │ ├── OrbitDslPlugin.kt │ │ │ │ ├── OrbitDslPlugins.kt │ │ │ │ └── Builder.kt │ │ │ ├── Orbit2Dsl.kt │ │ │ ├── Operator.kt │ │ │ └── simple │ │ │ │ ├── SimpleContext.kt │ │ │ │ └── SimpleSyntax.kt │ │ │ ├── ContainerDecorator.kt │ │ │ ├── ContainerHost.kt │ │ │ ├── CoroutineScopeExtensions.kt │ │ │ └── internal │ │ │ └── LazyCreateContainerDecorator.kt │ └── test │ │ └── kotlin │ │ └── com │ │ └── babylon │ │ └── orbit2 │ │ └── syntax │ │ └── strict │ │ └── OrbitDslPluginsTest.kt └── orbit-2-core_build.gradle.kts ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── artifacts │ ├── orbit_2_core_jvm.xml │ └── orbit_2_test_jvm.xml ├── runConfigurations.xml ├── copyright │ └── Babylon.xml └── jarRepositories.xml ├── README.md ├── .github └── workflows │ └── gradle-wrapper-validation.yml ├── NOTICE.md ├── orbit-2-livedata ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ │ └── com │ │ │ └── babylon │ │ │ └── orbit2 │ │ │ └── livedata │ │ │ ├── LiveDataDslPlugin.kt │ │ │ └── LiveDataOperator.kt │ └── test │ │ └── kotlin │ │ └── com │ │ └── babylon │ │ └── orbit2 │ │ └── livedata │ │ └── InstantTaskExecutorExtension.kt ├── README.md └── orbit-2-livedata_build.gradle.kts ├── orbit-2-viewmodel ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ │ └── com │ │ │ └── babylon │ │ │ └── orbit2 │ │ │ └── viewmodel │ │ │ ├── SavedStateContainerDecorator.kt │ │ │ └── AndroidIdlingResource.kt │ └── test │ │ └── koltin │ │ └── com │ │ └── babylon │ │ └── orbit2 │ │ └── viewmodel │ │ └── AndroidIdlingResourceRobolectricTest.kt └── orbit-2-viewmodel_build.gradle.kts ├── test-common ├── test-common_build.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ └── babylon │ └── orbit2 │ └── test │ ├── Assertions.kt │ └── ScopedBlockingWorkSimulator.kt ├── simple-syntax.md ├── strict-syntax.md ├── history.md ├── gradle.properties ├── orbit-2-coroutines ├── orbit-2-coroutines_build.gradle.kts ├── README.md └── src │ └── main │ └── kotlin │ └── com │ └── babylon │ └── orbit2 │ └── coroutines │ ├── TransformSuspend.kt │ └── TransformFlow.kt ├── settings.gradle.kts ├── orbit-2-rxjava2 ├── orbit-2-rxjava2_build.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ └── babylon │ └── orbit2 │ └── rxjava2 │ ├── RxJava2Maybe.kt │ ├── RxJava2Single.kt │ ├── RxJava2Completable.kt │ └── RxJava2Observable.kt ├── orbit-2-rxjava3 ├── orbit-2-rxjava3_build.gradle.kts └── src │ └── main │ └── kotlin │ └── com │ └── babylon │ └── orbit2 │ └── rxjava3 │ ├── RxJava3Maybe.kt │ ├── RxJava3Single.kt │ ├── RxJava3Completable.kt │ └── RxJava3Observable.kt ├── orbit-2-rxjava1 ├── orbit-2-rxjava1_build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ └── com │ │ └── babylon │ │ └── orbit2 │ │ └── rxjava1 │ │ ├── RxJava1Single.kt │ │ ├── RxJava1Completable.kt │ │ └── RxJava1Observable.kt └── README.md └── orbit-2-test ├── orbit-2-test_build.gradle.kts └── src ├── test └── kotlin │ └── com │ └── babylon │ └── orbit2 │ └── SideEffectTest.kt └── main └── kotlin └── com └── babylon └── orbit2 └── TestContainer.kt /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/slack-logo-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/images/slack-logo-icon.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/xml/backup_descriptor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | For all releases, please see [GitHub releases](https://github.com/babylonhealth/orbit-mvi/releases) 4 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Orbit Stock List 3 | 4 | -------------------------------------------------------------------------------- /orbit-2-core/docs/orbit-2-overview-1.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | A[UI] -->|actions| B(Business Component) 3 | B -->|events| C(Reducer) 4 | C -->|state updates| A -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /orbit-2-core/docs/orbit-2-overview-2.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | A[UI] -->|calls| B(ContainerHost) 3 | B --> C(Container) 4 | C --> D(Transformer) 5 | D -->|events| E(Reducer) 6 | E -->|state updates| A -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-posts/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #BCE5D6 4 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-calculator/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #262626 4 | 5 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/babylonhealth/orbit-mvi/HEAD/samples/orbit-2-stocklist/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #262626 4 | 5 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/idling/IdlingResource.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.idling 2 | 3 | public interface IdlingResource { 4 | public fun increment() 5 | public fun decrement() 6 | public fun close() 7 | } 8 | -------------------------------------------------------------------------------- /orbit-2-core/docs/orbit-2-overview-3.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | A[UI] -->|calls| B(ContainerHost) 3 | B --> C(Container) 4 | C --> D(Transformer) 5 | C --> D2(Side Effect) 6 | D2 -->|side effects| A 7 | D -->|events| E(Reducer) 8 | E -->|state updates| A -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/idling/NoopIdlingResource.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.idling 2 | 3 | public class NoopIdlingResource : IdlingResource { 4 | override fun increment(): Unit = Unit 5 | override fun decrement(): Unit = Unit 6 | override fun close(): Unit = Unit 7 | } 8 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | #1f000000 8 | 9 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Orbit Posts 3 | 4 | 5 | 6 | %d post 7 | %d comments 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/drawable/tick.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/artifacts/orbit_2_core_jvm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/orbit-2-core/build/libs 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/artifacts/orbit_2_test_jvm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/orbit-2-test/build/libs 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gradle/scripts/detekt.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 0 3 | 4 | formatting: 5 | MaximumLineLength: 6 | active: false 7 | 8 | style: 9 | MaxLineLength: 10 | maxLineLength: 145 # increased from 120 11 | MagicNumber: 12 | excludes: "**/test/**,**/androidTest/**,**Test.kt,**Spec.kt,**Spek.kt,**.kts" 13 | 14 | complexity: 15 | LongMethod: 16 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 17 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/drawable/arrow_up_bold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 for Kotlin and Android 2 | 3 | **This repository is no longer maintained, we cannot respond to issues 4 | or pull requests.** 5 | 6 | While we can’t officially endorse software we don’t write ourselves, the 7 | original maintainers are maintaining a fork of this project under 8 | [https://github.com/orbit-mvi/orbit-mvi](https://github.com/orbit-mvi/orbit-mvi). 9 | 10 | You can find the original README [here](readme-old.md) 11 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/drawable/arrow_down_bold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/values/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 72dp 5 | 16dp 6 | 1dp 7 | 24dp 8 | 24dp 9 | 10 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper-validation.yml: -------------------------------------------------------------------------------- 1 | name: "Validate Gradle Wrapper" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - orbit/main 8 | - feature/** 9 | tags: 10 | - '*' 11 | pull_request: 12 | branches: 13 | - main 14 | - orbit/main 15 | - feature/** 16 | 17 | jobs: 18 | validation: 19 | name: "Validation" 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: gradle/wrapper-validation-action@v1 24 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/SideEffectContext.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.syntax.strict 2 | 3 | import com.babylon.orbit2.Container 4 | import com.babylon.orbit2.syntax.Operator 5 | import com.babylon.orbit2.syntax.Orbit2Dsl 6 | 7 | /** 8 | * Represents the current context in which a side effect [Operator] is executing. 9 | */ 10 | @Orbit2Dsl 11 | public interface SideEffectContext : Context { 12 | /** 13 | * Posts a side effect to [Container.sideEffectFlow]. 14 | */ 15 | public suspend fun post(event: SE) 16 | } 17 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICES 2 | 3 | ## Orbit MVI 4 | 5 | Copyright © 2020 Babylon Partners Limited. 6 | 7 | This product includes software developed at [Babylon Health](http://www.babylonhealth.com/). 8 | 9 | This software uses the following open source works: 10 | 11 | - [Kotlin](https://github.com/JetBrains/kotlin) 12 | - [Android](https://developer.android.com) 13 | - [Orbit MVI](https://github.com/babylonhealth/orbit-mvi) 14 | - [Koin](https://insert-koin.io/) 15 | - [JUnit](https://junit.org/) 16 | - [Kotlin Fixture](https://github.com/appmattus/kotlinfixture/) 17 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICES 2 | 3 | ## Orbit MVI 4 | 5 | Copyright © 2020 Babylon Partners Limited. 6 | 7 | This product includes software developed at [Babylon Health](http://www.babylonhealth.com/). 8 | 9 | This software uses the following open source works: 10 | 11 | - [Kotlin](https://github.com/JetBrains/kotlin) 12 | - [Android](https://developer.android.com) 13 | - [Orbit MVI](https://github.com/babylonhealth/orbit-mvi) 14 | - [Lightstreamer](https://lightstreamer.com) 15 | - [Koin](https://insert-koin.io/) 16 | - [Groupie](https://github.com/lisawray/groupie) 17 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/idling/SimpleIdlingExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.idling 2 | 3 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 4 | 5 | public suspend fun OrbitDslPlugin.ContainerContext.withIdling( 6 | registerIdling: Boolean, 7 | block: suspend OrbitDslPlugin.ContainerContext.() -> Unit 8 | ) { 9 | if (registerIdling) settings.idlingRegistry.increment() 10 | return block().also { 11 | if (registerIdling) settings.idlingRegistry.decrement() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #f5f5f5 4 | @android:color/black 5 | 6 | @android:color/white 7 | 8 | #9c27b0 9 | #f44336 10 | #03a9f4 11 | #ff9800 12 | #4caf50 13 | 14 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/layout/post_list_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICES 2 | 3 | ## Orbit MVI 4 | 5 | Copyright © 2020 Babylon Partners Limited. 6 | 7 | This product includes software developed at [Babylon Health](http://www.babylonhealth.com/). 8 | 9 | This software uses the following open source works: 10 | 11 | - [Kotlin](https://github.com/JetBrains/kotlin) 12 | - [Android](https://developer.android.com) 13 | - [Markdown Lint plugin](https://github.com/appmattus/markdown-lint) 14 | - [Gradle Versions plugin](https://github.com/ben-manes/gradle-versions-plugin) 15 | - [Bintray plugin](https://github.com/bintray/gradle-bintray-plugin) 16 | - [Detekt](https://github.com/detekt/detekt) 17 | - [RxJava](https://github.com/ReactiveX/RxJava) 18 | - [JUnit](https://junit.org/) 19 | - [Kotest](https://kotest.io) 20 | 21 | See individual sample projects for their notices. 22 | -------------------------------------------------------------------------------- /.idea/copyright/Babylon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/Orbit2Dsl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax 18 | 19 | @DslMarker 20 | public annotation class Orbit2Dsl 21 | -------------------------------------------------------------------------------- /orbit-2-livedata/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /orbit-2-viewmodel/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/StrictSyntax.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.syntax.strict 2 | 3 | import com.babylon.orbit2.Container 4 | import com.babylon.orbit2.ContainerHost 5 | import com.babylon.orbit2.syntax.Orbit2Dsl 6 | import kotlinx.coroutines.flow.collect 7 | 8 | /** 9 | * Build and execute an orbit flow on [Container] using the [Builder] and 10 | * associated DSL functions. 11 | * 12 | * @param init lambda returning the operator chain that represents the flow 13 | */ 14 | @Orbit2Dsl 15 | public fun ContainerHost.orbit( 16 | init: Builder.() -> Builder 17 | ): Unit = container.orbit { 18 | Builder() 19 | .init() 20 | .build(this) 21 | .collect() 22 | } 23 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/common/NavigationEvent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.common 18 | 19 | interface NavigationEvent 20 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/Operator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax 18 | 19 | public interface Operator { 20 | public val registerIdling: Boolean 21 | } 22 | -------------------------------------------------------------------------------- /test-common/test-common_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | 21 | dependencies { 22 | implementation(kotlin("stdlib-jdk8")) 23 | implementation(ProjectDependencies.kotlinCoroutines) 24 | } 25 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator 18 | 19 | interface CalculatorState { 20 | val digitalDisplay: String 21 | } 22 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/layout/list_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICES 2 | 3 | ## Orbit MVI 4 | 5 | Copyright © 2020 Babylon Partners Limited. 6 | 7 | This product includes software developed at [Babylon Health](http://www.babylonhealth.com/). 8 | 9 | This software uses the following open source works: 10 | 11 | - [Kotlin](https://github.com/JetBrains/kotlin) 12 | - [Android](https://developer.android.com) 13 | - [Orbit MVI](https://github.com/babylonhealth/orbit-mvi) 14 | - [Koin](https://insert-koin.io/) 15 | - [OkHttp](https://square.github.io/okhttp/) 16 | - [Retrofit](https://square.github.io/retrofit/) 17 | - [Jackson](https://github.com/FasterXML/jackson) 18 | - [Glide](https://bumptech.github.io/glide/) 19 | - [Groupie](https://github.com/lisawray/groupie) 20 | - [JUnit](https://junit.org/) 21 | - [Mockito](https://site.mockito.org) 22 | - [Mockito-Kotlin](https://github.com/nhaarman/mockito-kotlin) 23 | - [Kotlin Fixture](https://github.com/appmattus/kotlinfixture/) 24 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/business/ListSideEffect.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.list.business 18 | 19 | sealed class ListSideEffect { 20 | data class NavigateToDetail(val itemName: String) : ListSideEffect() 21 | } 22 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/data/posts/model/PostData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.model 18 | 19 | data class PostData( 20 | val id: Int, 21 | val userId: Int, 22 | val title: String, 23 | val body: String 24 | ) 25 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/data/posts/network/AvatarUrlGenerator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.network 18 | 19 | class AvatarUrlGenerator { 20 | fun generateUrl(email: String) = "https://robohash.org/$email?set=set1" 21 | } 22 | -------------------------------------------------------------------------------- /orbit-2-livedata/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 LiveData plugin 2 | 3 | - [Orbit 2 LiveData plugin](#orbit-2-livedata-plugin) 4 | - [transformLiveData](#transformlivedata) 5 | 6 | The LiveData plugin provides 7 | [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) 8 | operators. 9 | 10 | ```kotlin 11 | implementation("com.babylon.orbit2:orbit-livedata:") 12 | ``` 13 | 14 | ## transformLiveData 15 | 16 | ``` kotlin 17 | fun subscribeToLocationUpdates(): LiveData() 18 | 19 | class ExampleViewModel : ContainerHost { 20 | ... 21 | 22 | fun startLocationTracking() = orbit { 23 | transformLiveData { subscribeToLocationUpdates() } 24 | .reduce { state.copy(currentLocation = event) } 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | You can use this operator to subscribe to a [LiveData](https://developer.android.com/topic/libraries/architecture/livedata). 31 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/data/posts/model/UserData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.model 18 | 19 | data class UserData( 20 | val id: Int, 21 | val name: String, 22 | val username: String, 23 | val email: String 24 | ) 25 | -------------------------------------------------------------------------------- /gradle/scripts/jacoco.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply() 18 | 19 | val jacocoTask = tasks.withType { 20 | reports { 21 | html.isEnabled = true 22 | xml.isEnabled = true 23 | csv.isEnabled = false 24 | } 25 | } 26 | 27 | tasks.withType { 28 | finalizedBy(jacocoTask) 29 | } 30 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/domain/repositories/PostRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.domain.repositories 18 | 19 | interface PostRepository { 20 | suspend fun getOverviews(): List 21 | suspend fun getDetail(id: Int): Status 22 | } 23 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/data/posts/model/CommentData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.model 18 | 19 | data class CommentData( 20 | val id: Int, 21 | val postId: Int, 22 | val name: String, 23 | val email: String, 24 | val body: String 25 | ) 26 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/domain/repositories/Status.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.domain.repositories 18 | 19 | sealed class Status { 20 | data class Success(val data: T) : Status() 21 | data class Failure(val exception: Exception) : Status() 22 | } 23 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Orbit Calculator 3 | 4 | C 5 | ± 6 | % 7 | 8 | ÷ 9 | × 10 | 11 | + 12 | 13 | = 14 | 15 | 0 16 | 1 17 | 2 18 | 3 19 | 4 20 | 5 21 | 6 22 | 7 23 | 8 24 | 9 25 | 26 | . 27 | 28 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/domain/repositories/PostDetail.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.domain.repositories 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | 22 | @Parcelize 23 | data class PostDetail( 24 | val id: Int, 25 | val body: String, 26 | val comments: List 27 | ) : Parcelable 28 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/domain/repositories/PostComment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.domain.repositories 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | 22 | @Parcelize 23 | data class PostComment( 24 | val id: Int, 25 | val name: String, 26 | val email: String, 27 | val body: String 28 | ) : Parcelable 29 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/business/ListState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.list.business 18 | 19 | import android.os.Parcelable 20 | import com.babylon.orbit2.sample.stocklist.streaming.stock.Stock 21 | import kotlinx.android.parcel.Parcelize 22 | 23 | @Parcelize 24 | data class ListState( 25 | val stocks: List = emptyList() 26 | ) : Parcelable 27 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/domain/repositories/PostOverview.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.domain.repositories 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | 22 | @Parcelize 23 | data class PostOverview( 24 | val id: Int, 25 | val avatarUrl: String, 26 | val title: String, 27 | val username: String 28 | ) : Parcelable 29 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/detail/business/DetailState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.detail.business 18 | 19 | import android.os.Parcelable 20 | import com.babylon.orbit2.sample.stocklist.streaming.stock.StockDetail 21 | import kotlinx.android.parcel.Parcelize 22 | 23 | @Parcelize 24 | data class DetailState( 25 | val stock: StockDetail? = null 26 | ) : Parcelable 27 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/simple/SimpleContext.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.simple 18 | 19 | import com.babylon.orbit2.syntax.Orbit2Dsl 20 | 21 | /** 22 | * Represents the current context in which a simple orbit is executing. 23 | * 24 | * @property state The current state of the container 25 | */ 26 | @Orbit2Dsl 27 | public interface SimpleContext { 28 | public val state: STATE 29 | } 30 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/streaming/stock/Stock.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.streaming.stock 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | 22 | @Parcelize 23 | data class Stock( 24 | val itemName: String, 25 | val name: String, 26 | val bid: String, 27 | val ask: String, 28 | val timestamp: String 29 | ) : Parcelable 30 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/OpenPostNavigationEvent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postlist.viewmodel 18 | 19 | import com.babylon.orbit2.sample.posts.app.common.NavigationEvent 20 | import com.babylon.orbit2.sample.posts.domain.repositories.PostOverview 21 | 22 | data class OpenPostNavigationEvent( 23 | val post: PostOverview 24 | ) : NavigationEvent 25 | -------------------------------------------------------------------------------- /simple-syntax.md: -------------------------------------------------------------------------------- 1 | # Simple syntax 2 | 3 | ``` kotlin 4 | class MyViewModel: ContainerHost, ViewModel() { 5 | 6 | override val container = container(MyState()) 7 | 8 | fun loadDataForId(id: Int) = intent { 9 | postSideEffect(MySideEffect.Toast("Loading data for $id!")) 10 | 11 | val result = repository.loadData(id) 12 | 13 | reduce { 14 | state.copy(data = result) 15 | } 16 | } 17 | } 18 | ``` 19 | 20 | This syntax integrates with the coroutine framework to bring you something that 21 | you will be very comfortable with if you already use coroutines for your 22 | project. On the other hand, it's slightly easier to make mistakes if you don't 23 | know how to use coroutines effectively. For example, blocking code in 24 | `intent` can block your `Container`. 25 | 26 | Pros: 27 | 28 | - Extremely light and flexible 29 | - Your MVI logic executes in a suspend function 30 | - Interoperability with e.g. RxJava achieved through standard Kotlin libraries 31 | 32 | Cons: 33 | 34 | - Your code has to conform to coroutine best practices 35 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/PostListState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postlist.viewmodel 18 | 19 | import android.os.Parcelable 20 | import com.babylon.orbit2.sample.posts.domain.repositories.PostOverview 21 | import kotlinx.android.parcel.Parcelize 22 | 23 | @Parcelize 24 | data class PostListState( 25 | val overviews: List = emptyList() 26 | ) : Parcelable 27 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/idling/OperatorIdlingExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.idling 2 | 3 | import com.babylon.orbit2.syntax.Operator 4 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.onCompletion 7 | import kotlinx.coroutines.flow.onStart 8 | 9 | public suspend fun , T> OrbitDslPlugin.ContainerContext<*, *>.withIdling( 10 | operator: O, 11 | block: suspend O.() -> T 12 | ): T { 13 | if (operator.registerIdling) settings.idlingRegistry.increment() 14 | return block(operator).also { 15 | if (operator.registerIdling) settings.idlingRegistry.decrement() 16 | } 17 | } 18 | 19 | @Suppress("EXPERIMENTAL_API_USAGE") 20 | public suspend fun , T> OrbitDslPlugin.ContainerContext<*, *>.withIdlingFlow( 21 | operator: O, 22 | block: suspend O.() -> Flow 23 | ): Flow { 24 | return block(operator) 25 | .onStart { if (operator.registerIdling) settings.idlingRegistry.increment() } 26 | .onCompletion { if (operator.registerIdling) settings.idlingRegistry.decrement() } 27 | } 28 | -------------------------------------------------------------------------------- /test-common/src/main/kotlin/com/babylon/orbit2/test/Assertions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.test 18 | 19 | import kotlinx.coroutines.withTimeout 20 | import kotlinx.coroutines.yield 21 | 22 | public suspend fun assertEventually(timeout: Long = 2000L, block: suspend () -> Unit) { 23 | withTimeout(timeout) { 24 | while (true) { 25 | try { 26 | block() 27 | break 28 | } catch (ignored: Throwable) { 29 | yield() 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/simple/SimpleSyntax.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.simple 18 | 19 | import com.babylon.orbit2.syntax.Orbit2Dsl 20 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 21 | 22 | @Orbit2Dsl 23 | public class SimpleSyntax(internal val containerContext: OrbitDslPlugin.ContainerContext) { 24 | 25 | /** 26 | * The current state which can change throughout execution of the orbit block 27 | */ 28 | public val state: S get() = containerContext.state 29 | } 30 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/test/kotlin/com/babylon/orbit2/sample/posts/data/posts/network/AvatarUrlGeneratorTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.network 18 | 19 | import org.junit.Assert.assertEquals 20 | import org.junit.jupiter.api.Test 21 | 22 | class AvatarUrlGeneratorTest { 23 | @Test 24 | fun `generate url based on parameter`() { 25 | val actual = AvatarUrlGenerator().generateUrl("peopleandperformance@babylonhealth.com") 26 | assertEquals("https://robohash.org/peopleandperformance@babylonhealth.com?set=set1", actual) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/Context.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import com.babylon.orbit2.syntax.Orbit2Dsl 21 | 22 | /** 23 | * Represents the current context in which an [Operator] is executing. 24 | * 25 | * @property state The state captured at the point when the operator is executed 26 | * @property event The current event being processed 27 | */ 28 | @Orbit2Dsl 29 | public interface Context { 30 | public val state: STATE 31 | public val event: EVENT 32 | } 33 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/VolatileContext.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import com.babylon.orbit2.syntax.Orbit2Dsl 21 | 22 | /** 23 | * Represents the current context in which an [Operator] is executing with access to the [volatileState]. 24 | */ 25 | @Orbit2Dsl 26 | public interface VolatileContext : Context { 27 | /** 28 | * The current state which can change throughout execution of the operator 29 | */ 30 | public fun volatileState(): STATE 31 | } 32 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/streaming/stock/StockDetail.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.streaming.stock 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | 22 | @Parcelize 23 | data class StockDetail( 24 | val itemName: String, 25 | val name: String, 26 | val pctChange: String, 27 | val bid: String, 28 | val bidQuantity: String, 29 | val ask: String, 30 | val askQuantity: String, 31 | val min: String, 32 | val max: String, 33 | val timestamp: String 34 | ) : Parcelable 35 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/ContainerDecorator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2 18 | 19 | /** 20 | * A decorator applying additional logic to a [Container]. 21 | * 22 | * @param STATE The container's state type. 23 | * @param SIDE_EFFECT The type of side effects posted by this container. Can be [Nothing] if this 24 | * container never posts side effects. 25 | */ 26 | public interface ContainerDecorator : Container { 27 | /** 28 | * The wrapped container. 29 | */ 30 | public val actual: Container 31 | } 32 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/sampledata/comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "name": "id labore ex et quam laborum", 5 | "email": "Eliseo@gardner.biz", 6 | "body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium" 7 | }, 8 | { 9 | "name": "quo vero reiciendis velit similique earum", 10 | "email": "Jayne_Kuhic@sydney.com", 11 | "body": "est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et" 12 | }, 13 | { 14 | "name": "odio adipisci rerum aut animi", 15 | "email": "Nikita@garfield.biz", 16 | "body": "quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione" 17 | }, 18 | { 19 | "name": "alias odio sit", 20 | "email": "Lew@alysha.tv", 21 | "body": "non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/PostsApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app 18 | 19 | import android.app.Application 20 | import com.babylon.orbit2.sample.posts.app.di.module 21 | import org.koin.android.ext.koin.androidContext 22 | import org.koin.core.context.startKoin 23 | 24 | @Suppress("unused") 25 | class PostsApplication : Application() { 26 | 27 | override fun onCreate() { 28 | super.onCreate() 29 | 30 | startKoin { 31 | androidContext(this@PostsApplication) 32 | modules(listOf(module())) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /strict-syntax.md: -------------------------------------------------------------------------------- 1 | # Strict syntax 2 | 3 | ``` kotlin 4 | class MyViewModel: ContainerHost, ViewModel() { 5 | 6 | override val container = container(MyState()) 7 | 8 | fun loadDataForId(id: Int) = orbit { 9 | sideEffect { post(MySideEffect.Toast("Loading data for $id!")) } 10 | .transformSuspend { repository.loadData(id) } 11 | .reduce { 12 | state.copy(data = result) 13 | } 14 | } 15 | } 16 | ``` 17 | 18 | The *classic* Orbit syntax is based on streams. It's close to how MVI is 19 | often portrayed - a reactive cycle. This syntax is great if you're in a 20 | legacy code base with lots of RxJava. Especially if you're thinking of 21 | migrating to coroutines, since you can mix and match both. However it's 22 | not as flexible as the simple syntax due to being stream-based. It's 23 | strictness can be an advantage in larger teams. 24 | 25 | Pros: 26 | 27 | - Relatively simple 28 | - Hard to make mistakes 29 | - Familiar if you use streams a lot 30 | - Great for code-bases where RxJava and coroutines are mixed 31 | 32 | Cons: 33 | 34 | - Control-flow logic (e.g. reducing conditionally) is awkward to create 35 | - Not as readable or flexible as the simple syntax 36 | - Interoperability with e.g. RxJava achieved through extra Orbit modules 37 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 20 | 21 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | # A bit of history 2 | 3 | We originally set out to create Orbit with the following principles in mind: 4 | 5 | - Simple 6 | - Flexible 7 | - Testable 8 | - Designed for, but not limited to Android 9 | 10 | Orbit 1 was our first attempt at this, and while it worked well in general, it 11 | fell short of our expectations when it came to its flexibility and testability. 12 | It did not support coroutines with support hard to incorporate, as it was 13 | rigidly dependent on RxJava 2. The users were not shielded from this either. As 14 | we were migrating to coroutines ourselves, this was increasing the complexity 15 | of our code. 16 | 17 | We thought we had taken Orbit 1 as far as we could. Having learned a great deal 18 | about MVI in Orbit 1, we set out to take another shot at this. We resolved to 19 | keep the good things of Orbit 1 and redesign it from the ground up to live up 20 | to our standards as Orbit 2. We think - hopefully, finally - we hit the sweet 21 | spot. 22 | 23 | We stand on the shoulders of giants: 24 | 25 | - [Managing State with RxJava by Jake Wharton](https://www.reddit.com/r/androiddev/comments/656ter/managing_state_with_rxjava_by_jake_wharton/) 26 | - [RxFeedback](https://github.com/NoTests/RxFeedback.kt) 27 | - [Mosby MVI](https://github.com/sockeqwe/mosby) 28 | - [MvRx](https://github.com/airbnb/MvRx) 29 | 30 | Thank you so much to everyone in the community for the support, whether direct 31 | or not. 32 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postdetails/viewmodel/PostDetailState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postdetails.viewmodel 18 | 19 | import android.os.Parcelable 20 | import com.babylon.orbit2.sample.posts.domain.repositories.PostDetail 21 | import com.babylon.orbit2.sample.posts.domain.repositories.PostOverview 22 | import kotlinx.android.parcel.Parcelize 23 | 24 | sealed class PostDetailState : Parcelable { 25 | 26 | abstract val postOverview: PostOverview 27 | 28 | @Parcelize 29 | data class Details(override val postOverview: PostOverview, val post: PostDetail) : PostDetailState() 30 | 31 | @Parcelize 32 | data class NoDetailsAvailable(override val postOverview: PostOverview) : PostDetailState() 33 | } 34 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator 18 | 19 | import android.os.Bundle 20 | import androidx.appcompat.app.AppCompatActivity 21 | import androidx.databinding.DataBindingUtil 22 | import com.babylon.orbit2.sample.calculator.databinding.ActivityMainBinding 23 | import org.koin.androidx.viewmodel.ext.android.getViewModel 24 | 25 | class CalculatorActivity : AppCompatActivity() { 26 | 27 | override fun onCreate(savedInstanceState: Bundle?) { 28 | super.onCreate(savedInstanceState) 29 | 30 | DataBindingUtil.setContentView(this, R.layout.activity_main).apply { 31 | viewmodel = getViewModel() 32 | lifecycleOwner = this@CalculatorActivity 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020 Babylon Partners Limited 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Project-wide Gradle settings. 18 | # IDE (e.g. Android Studio) users: 19 | # Gradle settings configured through the IDE *will override* 20 | # any settings specified in this file. 21 | # For more details on how to configure your build environment visit 22 | # http://www.gradle.org/docs/current/userguide/build_environment.html 23 | # Specifies the JVM arguments used for the daemon process. 24 | # The setting is particularly useful for tweaking memory settings. 25 | 26 | org.gradle.jvmargs=-Xmx1536m 27 | 28 | # When configured, Gradle will run in incubating parallel mode. 29 | # This option should only be used with decoupled projects. More details, visit 30 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 31 | # org.gradle.parallel=true 32 | 33 | android.useAndroidX=true 34 | android.enableJetifier=true 35 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 20 | 21 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/ContainerHost.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2 18 | 19 | /** 20 | * Apply this interface to anything you want to become an orbit container host. 21 | * Typically this will be an Android ViewModel but it can be applied to simple presenters etc. 22 | * 23 | * Extension functions `intent` and `orbit` are provided as a convenient way of launching orbit 24 | * flows on the container. 25 | */ 26 | public interface ContainerHost { 27 | /** 28 | * The orbit [Container] instance. 29 | * 30 | * Use factory functions to easily obtain a [Container] instance. 31 | * 32 | * ``` 33 | * override val container = scope.container(initialState) 34 | * ``` 35 | */ 36 | public val container: Container 37 | } 38 | -------------------------------------------------------------------------------- /orbit-2-coroutines/orbit-2-coroutines_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | 21 | dependencies { 22 | implementation(kotlin("stdlib-jdk8")) 23 | implementation(ProjectDependencies.kotlinCoroutines) 24 | 25 | api(project(":orbit-2-core")) 26 | 27 | // Testing 28 | testImplementation(project(":orbit-2-test")) 29 | testImplementation(project(":test-common")) 30 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 31 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 32 | } 33 | 34 | // Fix lack of source code when publishing pure Kotlin projects 35 | // See https://github.com/novoda/bintray-release/issues/262 36 | tasks.whenTaskAdded { 37 | if (name == "generateSourcesJarForMavenPublication") { 38 | this as Jar 39 | from(sourceSets.main.get().allSource) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/test/kotlin/com/babylon/orbit2/sample/calculator/livedata/MockLifecycleOwner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator.livedata 18 | 19 | import androidx.lifecycle.Lifecycle 20 | import androidx.lifecycle.LifecycleOwner 21 | import androidx.lifecycle.LifecycleRegistry 22 | 23 | internal class MockLifecycleOwner : LifecycleOwner { 24 | private val registry = LifecycleRegistry(this) 25 | 26 | var currentState: Lifecycle.State 27 | get() = registry.currentState 28 | set(value) { 29 | registry.currentState = value 30 | } 31 | 32 | val hasObservers: Boolean 33 | get() = registry.observerCount > 0 34 | 35 | fun dispatchEvent(event: Lifecycle.Event) { 36 | registry.handleLifecycleEvent(event) 37 | } 38 | 39 | override fun getLifecycle(): Lifecycle = registry 40 | } 41 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator 18 | 19 | import android.app.Application 20 | import androidx.lifecycle.SavedStateHandle 21 | import org.koin.android.ext.koin.androidContext 22 | import org.koin.androidx.viewmodel.dsl.viewModel 23 | import org.koin.core.context.startKoin 24 | import org.koin.dsl.module 25 | 26 | @Suppress("unused") 27 | class CalculatorApplication : Application() { 28 | 29 | override fun onCreate() { 30 | super.onCreate() 31 | 32 | startKoin { 33 | androidContext(this@CalculatorApplication) 34 | modules(listOf(mainModule)) 35 | } 36 | } 37 | 38 | private val mainModule = module { 39 | viewModel { (savedStateHandle: SavedStateHandle) -> CalculatorViewModel(savedStateHandle) } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | include( 18 | "orbit-2-core", 19 | "orbit-2-coroutines", 20 | "orbit-2-livedata", 21 | "orbit-2-rxjava1", 22 | "orbit-2-rxjava2", 23 | "orbit-2-rxjava3", 24 | "orbit-2-test", 25 | "orbit-2-viewmodel", 26 | "samples:orbit-2-calculator", 27 | "samples:orbit-2-posts", 28 | "samples:orbit-2-stocklist", 29 | "test-common" 30 | ) 31 | 32 | fun renameBuildFileToModuleName(project: ProjectDescriptor) { 33 | project.buildFileName = "${project.name}_build.gradle.kts" 34 | project.children.forEach { child -> renameBuildFileToModuleName(child) } 35 | } 36 | // Will rename every module's build.gradle file to use its name instead of `build`. 37 | // E.g. `app/build.gradle` will become `app/app.gradle` 38 | // The root build.gradle file will remain untouched 39 | rootProject.children.forEach { subproject -> renameBuildFileToModuleName(subproject) } 40 | -------------------------------------------------------------------------------- /orbit-2-rxjava2/orbit-2-rxjava2_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | 21 | dependencies { 22 | implementation(kotlin("stdlib-jdk8")) 23 | implementation(ProjectDependencies.rxJava2) 24 | api(ProjectDependencies.kotlinCoroutinesRx2) 25 | 26 | api(project(":orbit-2-core")) 27 | 28 | // Testing 29 | testImplementation(project(":orbit-2-test")) 30 | testImplementation(project(":test-common")) 31 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 32 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 33 | } 34 | 35 | // Fix lack of source code when publishing pure Kotlin projects 36 | // See https://github.com/novoda/bintray-release/issues/262 37 | tasks.whenTaskAdded { 38 | if (name == "generateSourcesJarForMavenPublication") { 39 | this as Jar 40 | from(sourceSets.main.get().allSource) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /orbit-2-rxjava3/orbit-2-rxjava3_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | 21 | dependencies { 22 | implementation(kotlin("stdlib-jdk8")) 23 | implementation(ProjectDependencies.rxJava3) 24 | api(ProjectDependencies.kotlinCoroutinesRx3) 25 | 26 | api(project(":orbit-2-core")) 27 | 28 | // Testing 29 | testImplementation(project(":orbit-2-test")) 30 | testImplementation(project(":test-common")) 31 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 32 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 33 | } 34 | 35 | // Fix lack of source code when publishing pure Kotlin projects 36 | // See https://github.com/novoda/bintray-release/issues/262 37 | tasks.whenTaskAdded { 38 | if (name == "generateSourcesJarForMavenPublication") { 39 | this as Jar 40 | from(sourceSets.main.get().allSource) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /orbit-2-rxjava1/orbit-2-rxjava1_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | 21 | dependencies { 22 | implementation(kotlin("stdlib-jdk8")) 23 | implementation(ProjectDependencies.rxJava1) 24 | implementation(ProjectDependencies.kotlinCoroutines) 25 | 26 | api(project(":orbit-2-core")) 27 | 28 | // Testing 29 | testImplementation(project(":orbit-2-test")) 30 | testImplementation(project(":test-common")) 31 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 32 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 33 | } 34 | 35 | // Fix lack of source code when publishing pure Kotlin projects 36 | // See https://github.com/novoda/bintray-release/issues/262 37 | tasks.whenTaskAdded { 38 | if (name == "generateSourcesJarForMavenPublication") { 39 | this as Jar 40 | from(sourceSets.main.get().allSource) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/sampledata/posts.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "post_username": "Leanne Graham", 5 | "post_title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 6 | "post_comments": "10 comments", 7 | "post_body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 8 | }, 9 | { 10 | "post_username": "Ervin Howell", 11 | "post_title": "qui est esse", 12 | "post_comments": "1 comment", 13 | "post_body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 14 | }, 15 | { 16 | "post_username": "Clementine Bauch", 17 | "post_title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", 18 | "post_comments": "0 comments", 19 | "post_body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" 20 | }, 21 | { 22 | "post_username": "Patricia Lebsack", 23 | "post_title": "eum et est occaecati", 24 | "post_comments": "5 comments", 25 | "post_body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /orbit-2-test/orbit-2-test_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | apply() 21 | 22 | dependencies { 23 | implementation(kotlin("stdlib-jdk8")) 24 | implementation(ProjectDependencies.kotlinCoroutines) 25 | implementation(kotlin("test")) 26 | 27 | api(project(":orbit-2-core")) 28 | 29 | // Testing 30 | testImplementation(kotlin("test")) 31 | testImplementation(kotlin("test-junit")) 32 | testImplementation(ProjectDependencies.kotestAssertions) 33 | testImplementation(ProjectDependencies.kotlinCoroutinesTest) 34 | } 35 | 36 | // Fix lack of source code when publishing pure Kotlin projects 37 | // See https://github.com/novoda/bintray-release/issues/262 38 | tasks.whenTaskAdded { 39 | if (name == "generateSourcesJarForMavenPublication") { 40 | this as Jar 41 | from(sourceSets.main.get().allSource) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /orbit-2-livedata/orbit-2-livedata_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | id("com.android.library") 19 | kotlin("android") 20 | } 21 | 22 | dependencies { 23 | implementation(kotlin("stdlib-jdk8")) 24 | implementation(ProjectDependencies.androidxLifecycleComponents) 25 | implementation(ProjectDependencies.androidxLiveDataKtx) 26 | implementation(ProjectDependencies.kotlinCoroutines) 27 | implementation(ProjectDependencies.kotlinCoroutinesAndroid) 28 | 29 | api(project(":orbit-2-core")) 30 | 31 | // Testing 32 | testImplementation(project(":orbit-2-test")) 33 | testImplementation(project(":test-common")) 34 | testImplementation(ProjectDependencies.androidxTesting) 35 | testImplementation(ProjectDependencies.kotlinCoroutines) 36 | testImplementation(ProjectDependencies.kotlinCoroutinesTest) 37 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 38 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 39 | } 40 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/OrbitDslPlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | import com.babylon.orbit2.Container 20 | import com.babylon.orbit2.syntax.Operator 21 | import kotlinx.coroutines.flow.Flow 22 | 23 | /** 24 | * Extend this interface to create your own DSL plugin. 25 | */ 26 | public interface OrbitDslPlugin { 27 | public fun apply( 28 | containerContext: ContainerContext, 29 | flow: Flow, 30 | operator: Operator, 31 | createContext: (event: E) -> VolatileContext 32 | ): Flow 33 | 34 | public class ContainerContext( 35 | public val settings: Container.Settings, 36 | public val postSideEffect: suspend (SE) -> Unit, 37 | private val getState: () -> S, 38 | public val reduce: suspend ((S) -> S) -> Unit 39 | ) { 40 | public val state: S 41 | get() = getState() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /orbit-2-core/orbit-2-core_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | kotlin("jvm") 19 | } 20 | apply() 21 | 22 | dependencies { 23 | implementation(kotlin("stdlib-jdk8")) 24 | implementation(ProjectDependencies.kotlinCoroutines) 25 | 26 | compileOnly(ProjectDependencies.androidxAnnotation) 27 | 28 | // Testing 29 | testImplementation(project(":orbit-2-test")) 30 | testImplementation(project(":test-common")) 31 | testImplementation(kotlin("test")) 32 | testImplementation(kotlin("test-junit")) 33 | testImplementation(ProjectDependencies.kotlinCoroutinesTest) 34 | testImplementation(ProjectDependencies.kotestAssertions) 35 | } 36 | 37 | // Fix lack of source code when publishing pure Kotlin projects 38 | // See https://github.com/novoda/bintray-release/issues/262 39 | tasks.whenTaskAdded { 40 | if (name == "generateSourcesJarForMavenPublication") { 41 | this as Jar 42 | from(sourceSets.main.get().allSource) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features 18 | 19 | import android.os.Bundle 20 | import androidx.appcompat.app.AppCompatActivity 21 | import androidx.appcompat.widget.Toolbar 22 | import androidx.navigation.findNavController 23 | import androidx.navigation.ui.setupActionBarWithNavController 24 | import com.babylon.orbit2.sample.posts.R 25 | 26 | class MainActivity : AppCompatActivity() { 27 | 28 | private val navController by lazy { findNavController(R.id.nav_host_fragment) } 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | super.onCreate(savedInstanceState) 32 | setContentView(R.layout.main_activity) 33 | 34 | findViewById(R.id.toolbar).apply { 35 | setSupportActionBar(this) 36 | } 37 | 38 | setupActionBarWithNavController(navController) 39 | } 40 | 41 | override fun onSupportNavigateUp() = navController.navigateUp() 42 | } 43 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/data/posts/network/TypicodeService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.data.posts.network 18 | 19 | import com.babylon.orbit2.sample.posts.data.posts.model.CommentData 20 | import com.babylon.orbit2.sample.posts.data.posts.model.PostData 21 | import com.babylon.orbit2.sample.posts.data.posts.model.UserData 22 | import retrofit2.http.GET 23 | import retrofit2.http.Path 24 | 25 | // https://jsonplaceholder.typicode.com 26 | interface TypicodeService { 27 | @GET("posts/{id}") 28 | suspend fun post(@Path("id") id: Int): PostData 29 | 30 | @GET("posts") 31 | suspend fun posts(): List 32 | 33 | @GET("users/{id}") 34 | suspend fun user(@Path("id") id: Int): UserData 35 | 36 | @GET("users") 37 | suspend fun users(): List 38 | 39 | @GET("comments") 40 | suspend fun comments(): List 41 | 42 | @GET("posts/{id}/comments") 43 | suspend fun comments(@Path("id") postId: Int): List 44 | } 45 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 Sample - Stock List 2 | 3 | This sample implements a stock list using [Orbit MVI](https://github.com/babylonhealth/orbit-mvi). 4 | 5 | - The application uses the [strict syntax](../../strict-syntax.md). 6 | 7 | - The application uses Koin for dependency injection which is initialised in 8 | [StockListApplication](src/main/kotlin/com/babylon/orbit2/sample/stocklist/StockListApplication.kt). 9 | 10 | - Streaming data is provided by [Lightstreamer](https://lightstreamer.com) and 11 | their demo server with callback interfaces converted to Kotlin Flow's with 12 | [callbackFlow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html). 13 | 14 | - Navigation between the stock list and the detail view uses Jetpack's [Navigation](https://developer.android.com/guide/navigation) 15 | and [Safe Args](https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args). 16 | [ListViewModel](src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/business/ListViewModel.kt) 17 | posts a side effect which [ListFragment](src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/ui/ListFragment.kt) 18 | observes and sends to the `NavController`. 19 | 20 | - Both [ListViewModel](src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/business/ListViewModel.kt) 21 | and [DetailViewModel](src/main/kotlin/com/babylon/orbit2/sample/stocklist/detail/business/DetailViewModel.kt) 22 | use `transformFlow` to receive the streaming data before reducing it to the 23 | UI. 24 | 25 | - [Data Binding Library](https://developer.android.com/topic/libraries/data-binding) 26 | is used to populate layouts throughout. 27 | -------------------------------------------------------------------------------- /orbit-2-coroutines/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 Coroutines plugin 2 | 3 | - [Orbit 2 Coroutines plugin](#orbit-2-coroutines-plugin) 4 | - [transformSuspend](#transformsuspend) 5 | - [transformFlow](#transformflow) 6 | 7 | The coroutine plugin provides Coroutine Orbit operators. 8 | 9 | ```kotlin 10 | implementation("com.babylon.orbit2:orbit-coroutines:") 11 | ``` 12 | 13 | ## transformSuspend 14 | 15 | ``` kotlin 16 | suspend fun apiCall(): SomeResult { ... } 17 | suspend fun anotherApiCall(param: SomeResult): OtherResult { ... } 18 | 19 | class ExampleViewModel : ContainerHost { 20 | ... 21 | 22 | fun example(number: Int) = orbit { 23 | transformSuspend { delay(100) } 24 | } 25 | } 26 | fun anotherExample() = orbit { 27 | transformSuspend { apiCall() } 28 | .transformSuspend { anotherApiCall(event) } // "event" is the result of the first api call 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | Suspending transformers allow you to call suspending functions 35 | 36 | ## transformFlow 37 | 38 | ``` kotlin 39 | fun subscribeToLocationUpdates(): Flow { ... } 40 | 41 | class ExampleViewModel : ContainerHost { 42 | ... 43 | 44 | fun startLocationTracking() = orbit { 45 | transformFlow { subscribeToLocationUpdates() } 46 | .reduce { state.copy(currentLocation = event) } 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | You can use this operator to subscribe to hot or cold coroutine flows. The flows 53 | will emit until completion or until the 54 | [Container](../orbit-2-core/src/main/kotlin/com/babylon/orbit2/Container.kt) has 55 | been closed. 56 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/OrbitDslPlugins.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | /** 20 | * Orbit DSL plugin registry. In order for DSL extensions to work they need to be registered here 21 | * before use. 22 | * 23 | * The base DSL provided by [BaseDslPlugin] does not have to be registered as it is registered 24 | * implicitly, even after a [reset]. 25 | */ 26 | public object OrbitDslPlugins { 27 | 28 | internal var plugins: Set = setOf(BaseDslPlugin) 29 | private set 30 | 31 | /** 32 | * Register DSL plugins. This has to be done before using the DSL provided by the plugin. 33 | * 34 | * @param plugin The DSL plugin to register 35 | */ 36 | public fun register(plugin: OrbitDslPlugin) { 37 | if (!plugins.contains(plugin)) { 38 | plugins = plugins + plugin 39 | } 40 | } 41 | 42 | /** 43 | * Clears all registered plugins apart from the [BaseDslPlugin]. 44 | */ 45 | public fun reset() { 46 | plugins = setOf(BaseDslPlugin) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /orbit-2-viewmodel/orbit-2-viewmodel_build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | id("com.android.library") 19 | kotlin("android") 20 | id("kotlin-android-extensions") 21 | } 22 | 23 | dependencies { 24 | implementation(kotlin("stdlib-jdk8")) 25 | implementation(ProjectDependencies.kotlinCoroutines) 26 | 27 | api(project(":orbit-2-core")) 28 | 29 | implementation(ProjectDependencies.androidxLifecycleSavedState) 30 | implementation(ProjectDependencies.androidxLifecycleKtx) 31 | implementation(ProjectDependencies.androidxEspressoIdlingResource) 32 | 33 | // Testing 34 | testImplementation(project(":orbit-2-test")) 35 | testImplementation(project(":test-common")) 36 | testImplementation(project(":orbit-2-coroutines")) 37 | testImplementation(ProjectDependencies.androidxEspressoCore) 38 | testImplementation(ProjectDependencies.robolectric) 39 | 40 | GroupedDependencies.testsImplementation.forEach { testImplementation(it) } 41 | testRuntimeOnly(ProjectDependencies.junitJupiterEngine) 42 | } 43 | 44 | android { 45 | testOptions.unitTests.isIncludeAndroidResources = true 46 | } 47 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 Sample - Posts 2 | 3 | This sample implements a simple master-detail application using 4 | [Orbit MVI](https://github.com/babylonhealth/orbit-mvi). 5 | 6 | - The application uses the [simple syntax](../../simple-syntax.md). 7 | 8 | - The application uses Koin for dependency injection which is initialised in 9 | [PostsApplication](src/main/kotlin/com/babylon/orbit2/sample/posts/app//PostsApplication.kt). 10 | 11 | - [PostListViewModel](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/PostListViewModel.kt) 12 | loads a list of posts. Upon clicking a post it navigates to the 13 | [PostDetailsFragment](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postdetails/ui/PostDetailsFragment.kt) 14 | which displays the details of the clicked post. 15 | 16 | - Navigation between the list and the detail view uses Jetpack's 17 | [Navigation](https://developer.android.com/guide/navigation) and 18 | [SafeArgs](https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args). 19 | [PostListViewModel](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/PostListViewModel.kt) 20 | posts a side effect which 21 | [PostListFragment](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/ui/PostListFragment.kt) 22 | observes and sends to the `NavController`. 23 | 24 | - The state is accessed in the fragments through `Flow`. 25 | 26 | - [PostListViewModel](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/PostListViewModel.kt) 27 | and 28 | [PostDetailsViewModel](src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postdetails/viewmodel/PostDetailsViewModel.kt) 29 | use a `SavedStateHandle` for retaining the current state. 30 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/ui/TickAnimation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.list.ui 18 | 19 | import android.view.View 20 | import android.widget.TextView 21 | import kotlinx.coroutines.GlobalScope 22 | import kotlinx.coroutines.Job 23 | import kotlinx.coroutines.async 24 | import kotlinx.coroutines.delay 25 | 26 | fun animateChange(textView: TextView, tick: CheckableImageView, newValue: String, jobReference: JobHolder) { 27 | val currentValue = textView.text.toString() 28 | if (newValue != currentValue && currentValue.isNotEmpty()) { 29 | val diff = newValue.toDouble().compareTo(currentValue.toDouble()) 30 | 31 | if (diff != 0) { 32 | tick.isChecked = diff > 0 33 | tick.visibility = View.VISIBLE 34 | 35 | jobReference.job?.cancel() 36 | 37 | jobReference.job = GlobalScope.async { 38 | @Suppress("MagicNumber") 39 | (delay(300)) 40 | 41 | tick.visibility = View.INVISIBLE 42 | } 43 | } 44 | } 45 | } 46 | 47 | class JobHolder(var job: Job? = null) 48 | -------------------------------------------------------------------------------- /gradle/scripts/detekt.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import io.gitlab.arturbosch.detekt.Detekt 18 | import io.gitlab.arturbosch.detekt.DetektPlugin 19 | 20 | buildscript { 21 | repositories { 22 | maven(url = "https://plugins.gradle.org/m2/") 23 | } 24 | dependencies { 25 | classpath(PluginDependencies.detekt) 26 | } 27 | } 28 | 29 | repositories { 30 | jcenter() 31 | } 32 | 33 | apply() 34 | 35 | tasks.named("detekt", Detekt::class.java).configure { 36 | setSource(files(rootProject.projectDir)) 37 | 38 | include("**/*.kt") 39 | include("**/*.kts") 40 | exclude("**/resources/**") 41 | exclude("**/build/**") 42 | 43 | parallel = true 44 | 45 | autoCorrect = true 46 | buildUponDefaultConfig = true 47 | config.setFrom(files("${rootProject.projectDir}/gradle/scripts/detekt.yml")) 48 | 49 | reports { 50 | xml { 51 | enabled = true 52 | destination = file("build/reports/detekt/detekt.xml") 53 | } 54 | html { 55 | enabled = true 56 | } 57 | } 58 | } 59 | 60 | dependencies { 61 | "detektPlugins"(ProjectDependencies.detektFormatting) 62 | } 63 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 24 | 25 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /gradle/scripts/jacoco-android.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply() 18 | 19 | val jacocoTask = tasks.register("jacocoTestReport") { 20 | dependsOn(tasks.named("testDebugUnitTest")) 21 | 22 | reports { 23 | html.isEnabled = true 24 | xml.isEnabled = true 25 | csv.isEnabled = false 26 | } 27 | 28 | val fileFilter = listOf( 29 | "**/R.class", 30 | "**/R\$*.class", 31 | "**/BuildConfig.*", 32 | "**/Manifest*.*", 33 | "**/*Test*.*", 34 | "android/**/*.*" 35 | ) 36 | val debugTree = fileTree("${project.buildDir}/intermediates/javac/debug") { 37 | exclude(fileFilter) 38 | } 39 | 40 | val mainSrc = "${project.projectDir}/src/main/kotlin" 41 | 42 | sourceDirectories.setFrom(files(listOf(mainSrc))) 43 | classDirectories.setFrom(files(listOf(debugTree))) 44 | executionData.setFrom( 45 | fileTree(project.buildDir) { 46 | include(listOf("jacoco/testDebugUnitTest.exec")) 47 | } 48 | ) 49 | } 50 | 51 | tasks.withType { 52 | finalizedBy(jacocoTask) 53 | extensions.getByType().isIncludeNoLocationClasses = true 54 | } 55 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/detail/business/DetailViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.detail.business 18 | 19 | import androidx.lifecycle.SavedStateHandle 20 | import androidx.lifecycle.ViewModel 21 | import com.babylon.orbit2.ContainerHost 22 | import com.babylon.orbit2.coroutines.transformFlow 23 | import com.babylon.orbit2.sample.stocklist.streaming.stock.StockRepository 24 | import com.babylon.orbit2.syntax.strict.orbit 25 | import com.babylon.orbit2.syntax.strict.reduce 26 | import com.babylon.orbit2.viewmodel.container 27 | 28 | class DetailViewModel( 29 | savedStateHandle: SavedStateHandle, 30 | private val itemName: String, 31 | private val stockRepository: StockRepository 32 | ) : ViewModel(), ContainerHost { 33 | 34 | override val container = 35 | container(DetailState(), savedStateHandle) { requestStock() } 36 | 37 | private fun requestStock(): Unit = orbit { 38 | transformFlow { 39 | stockRepository.stockDetails(itemName) 40 | }.reduce { 41 | state.copy(stock = event) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 29 | 30 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /orbit-2-livedata/src/test/kotlin/com/babylon/orbit2/livedata/InstantTaskExecutorExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.livedata 18 | 19 | import androidx.arch.core.executor.ArchTaskExecutor 20 | import androidx.arch.core.executor.TaskExecutor 21 | import org.junit.jupiter.api.extension.AfterEachCallback 22 | import org.junit.jupiter.api.extension.BeforeEachCallback 23 | import org.junit.jupiter.api.extension.ExtensionContext 24 | 25 | class InstantTaskExecutorExtension : BeforeEachCallback, AfterEachCallback { 26 | override fun beforeEach(context: ExtensionContext?) { 27 | ArchTaskExecutor.getInstance().setDelegate( 28 | object : TaskExecutor() { 29 | override fun executeOnDiskIO(runnable: Runnable) { 30 | runnable.run() 31 | } 32 | 33 | override fun postToMainThread(runnable: Runnable) { 34 | runnable.run() 35 | } 36 | 37 | override fun isMainThread(): Boolean { 38 | return true 39 | } 40 | } 41 | ) 42 | } 43 | 44 | override fun afterEach(context: ExtensionContext?) { 45 | ArchTaskExecutor.getInstance().setDelegate(null) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postdetails/ui/PostCommentItem.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postdetails.ui 18 | 19 | import android.widget.TextView 20 | import com.babylon.orbit2.sample.posts.R 21 | import com.babylon.orbit2.sample.posts.domain.repositories.PostComment 22 | import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder 23 | import com.xwray.groupie.kotlinandroidextensions.Item 24 | 25 | data class PostCommentItem(private val post: PostComment) : Item() { 26 | 27 | override fun isSameAs(other: com.xwray.groupie.Item<*>) = other is PostCommentItem && post.id == other.post.id 28 | 29 | override fun hasSameContentAs(other: com.xwray.groupie.Item<*>) = other is PostCommentItem && post == other.post 30 | 31 | override fun getLayout() = R.layout.post_comment_list_item 32 | 33 | override fun bind(viewHolder: GroupieViewHolder, position: Int) { 34 | viewHolder.itemView.apply { 35 | findViewById(R.id.comment_username).text = post.name 36 | findViewById(R.id.comment_email).text = post.email 37 | findViewById(R.id.comment_body).text = post.body 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 Sample - Calculator 2 | 3 | This sample implements a simple calculator using [Orbit MVI](https://github.com/babylonhealth/orbit-mvi). 4 | 5 | - The application uses the [simple syntax](../../simple-syntax.md). 6 | 7 | - The application uses Koin for dependency injection which is initialised in 8 | [CalculatorApplication](src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorApplication.kt). 9 | 10 | - [CalculatorActivity](src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorActivity.kt) 11 | uses the [Data Binding Library](https://developer.android.com/topic/libraries/data-binding) 12 | to provide the [CalculatorViewModel](src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorViewModel.kt) 13 | to the layout [activity_main.xml](src/main/res/layout/activity_main.xml). The 14 | layout accesses the current state through LiveData. 15 | 16 | - [CalculatorViewModel](src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorViewModel.kt) 17 | uses a `SavedStateHandle` for retaining the current state. It implements a 18 | private [ContainerHost](../../orbit-2-core/src/main/kotlin/com/babylon/orbit2/ContainerHost.kt) 19 | so the internal implementation of [CalculatorState](src/main/kotlin/com/babylon/orbit2/sample/calculator/CalculatorState.kt) 20 | is not exposed. 21 | 22 | ## How the calculator works 23 | 24 | The calculator itself is based off the principle of two registers, x and y. In 25 | short: 26 | 27 | - Digits are stored in the x register. 28 | - The x register is rendered to screen unless it is empty in which case we 29 | render the y register. 30 | - Plus, minus, multiply and divide operators transfer data from x to y register 31 | and then clears x. The operator is stored as it is not actioned immediately. 32 | - Equals operator performs the calculation using the stored operator and the 33 | values in the x and y registers. 34 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/test/kotlin/com/babylon/orbit2/sample/posts/InstantTaskExecutorExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts 18 | 19 | import androidx.arch.core.executor.ArchTaskExecutor 20 | import androidx.arch.core.executor.TaskExecutor 21 | import org.junit.jupiter.api.extension.AfterEachCallback 22 | import org.junit.jupiter.api.extension.BeforeEachCallback 23 | import org.junit.jupiter.api.extension.ExtensionContext 24 | 25 | class InstantTaskExecutorExtension : BeforeEachCallback, AfterEachCallback { 26 | override fun beforeEach(context: ExtensionContext?) { 27 | ArchTaskExecutor.getInstance().setDelegate( 28 | object : TaskExecutor() { 29 | override fun executeOnDiskIO(runnable: Runnable) { 30 | runnable.run() 31 | } 32 | 33 | override fun postToMainThread(runnable: Runnable) { 34 | runnable.run() 35 | } 36 | 37 | override fun isMainThread(): Boolean { 38 | return true 39 | } 40 | } 41 | ) 42 | } 43 | 44 | override fun afterEach(context: ExtensionContext?) { 45 | ArchTaskExecutor.getInstance().setDelegate(null) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist 18 | 19 | import android.os.Bundle 20 | import androidx.appcompat.app.AppCompatActivity 21 | import androidx.appcompat.widget.Toolbar 22 | import androidx.navigation.findNavController 23 | import androidx.navigation.ui.setupActionBarWithNavController 24 | import com.babylon.orbit2.sample.stocklist.streaming.StreamingClient 25 | import org.koin.android.ext.android.inject 26 | 27 | class MainActivity : AppCompatActivity() { 28 | 29 | private val navController by lazy { findNavController(R.id.nav_host_fragment) } 30 | 31 | private val streamingClient by inject() 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | setContentView(R.layout.main_activity) 36 | 37 | findViewById(R.id.toolbar).apply { 38 | setSupportActionBar(this) 39 | setLogo(R.drawable.ic_orbit_toolbar) 40 | } 41 | 42 | setupActionBarWithNavController(navController) 43 | 44 | lifecycle.addObserver(streamingClient) 45 | } 46 | 47 | override fun onSupportNavigateUp() = navController.navigateUp() 48 | } 49 | -------------------------------------------------------------------------------- /orbit-2-viewmodel/src/main/kotlin/com/babylon/orbit2/viewmodel/SavedStateContainerDecorator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.viewmodel 18 | 19 | import androidx.lifecycle.SavedStateHandle 20 | import com.babylon.orbit2.Container 21 | import com.babylon.orbit2.ContainerDecorator 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 23 | import kotlinx.coroutines.flow.Flow 24 | import kotlinx.coroutines.flow.collect 25 | import kotlinx.coroutines.flow.flow 26 | 27 | internal class SavedStateContainerDecorator( 28 | override val actual: Container, 29 | private val savedStateHandle: SavedStateHandle 30 | ) : ContainerDecorator { 31 | override val currentState: STATE 32 | get() = actual.currentState 33 | 34 | override val stateFlow: Flow 35 | get() = flow { 36 | actual.stateFlow.collect { 37 | savedStateHandle[SAVED_STATE_KEY] = it 38 | emit(it) 39 | } 40 | } 41 | override val sideEffectFlow: Flow 42 | get() = actual.sideEffectFlow 43 | 44 | override fun orbit(orbitFlow: suspend OrbitDslPlugin.ContainerContext.() -> Unit) = 45 | actual.orbit(orbitFlow) 46 | } 47 | -------------------------------------------------------------------------------- /test-common/src/main/kotlin/com/babylon/orbit2/test/ScopedBlockingWorkSimulator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.test 18 | 19 | import kotlinx.coroutines.CoroutineScope 20 | import kotlinx.coroutines.Dispatchers 21 | import kotlinx.coroutines.Job 22 | import kotlinx.coroutines.channels.awaitClose 23 | import kotlinx.coroutines.channels.produce 24 | import kotlinx.coroutines.currentCoroutineContext 25 | import kotlinx.coroutines.isActive 26 | import kotlinx.coroutines.launch 27 | import kotlinx.coroutines.runBlocking 28 | 29 | @Suppress("EXPERIMENTAL_API_USAGE") 30 | public class ScopedBlockingWorkSimulator(private val scope: CoroutineScope) { 31 | 32 | private var job: Job? = null 33 | 34 | init { 35 | scope.produce(Dispatchers.Unconfined) { 36 | awaitClose { 37 | job?.cancel() 38 | } 39 | } 40 | } 41 | 42 | @Suppress("ControlFlowWithEmptyBody", "EmptyWhileBlock") 43 | public fun simulateWork() { 44 | if (job != null) { 45 | throw IllegalStateException("Can be invoked only once") 46 | } 47 | job = scope.launch { 48 | while (currentCoroutineContext().isActive) { 49 | } 50 | } 51 | runBlocking(job!!) { job!!.join() } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/test/kotlin/com/babylon/orbit2/sample/calculator/livedata/InstantTaskExecutorExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator.livedata 18 | 19 | import androidx.arch.core.executor.ArchTaskExecutor 20 | import androidx.arch.core.executor.TaskExecutor 21 | import org.junit.jupiter.api.extension.AfterEachCallback 22 | import org.junit.jupiter.api.extension.BeforeEachCallback 23 | import org.junit.jupiter.api.extension.ExtensionContext 24 | 25 | class InstantTaskExecutorExtension : BeforeEachCallback, AfterEachCallback { 26 | override fun beforeEach(context: ExtensionContext?) { 27 | ArchTaskExecutor.getInstance().setDelegate( 28 | object : TaskExecutor() { 29 | override fun executeOnDiskIO(runnable: Runnable) { 30 | runnable.run() 31 | } 32 | 33 | override fun postToMainThread(runnable: Runnable) { 34 | runnable.run() 35 | } 36 | 37 | override fun isMainThread(): Boolean { 38 | return true 39 | } 40 | } 41 | ) 42 | } 43 | 44 | override fun afterEach(context: ExtensionContext?) { 45 | ArchTaskExecutor.getInstance().setDelegate(null) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-core/src/test/kotlin/com/babylon/orbit2/syntax/strict/OrbitDslPluginsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import io.kotest.matchers.collections.shouldContainExactly 21 | import kotlinx.coroutines.flow.Flow 22 | import kotlin.test.AfterTest 23 | import kotlin.test.Test 24 | 25 | internal class OrbitDslPluginsTest { 26 | 27 | @AfterTest 28 | fun afterEach() { 29 | OrbitDslPlugins.reset() 30 | } 31 | 32 | @Test 33 | fun `base plugin is present by default`() { 34 | OrbitDslPlugins.plugins.shouldContainExactly(BaseDslPlugin) 35 | } 36 | 37 | @Test 38 | fun `base plugin is present after another plugin has been added`() { 39 | 40 | OrbitDslPlugins.register(TestPlugin) 41 | 42 | OrbitDslPlugins.plugins.shouldContainExactly(BaseDslPlugin, TestPlugin) 43 | } 44 | 45 | private object TestPlugin : OrbitDslPlugin { 46 | override fun apply( 47 | containerContext: OrbitDslPlugin.ContainerContext, 48 | flow: Flow, 49 | operator: Operator, 50 | createContext: (event: E) -> VolatileContext 51 | ): Flow { 52 | return flow 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /orbit-2-test/src/test/kotlin/com/babylon/orbit2/SideEffectTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2 18 | 19 | import kotlinx.coroutines.ExperimentalCoroutinesApi 20 | import kotlin.test.Test 21 | 22 | @ExperimentalCoroutinesApi 23 | internal class SideEffectTest { 24 | @Test 25 | fun `BLOCKING - succeeds if posted side effects match expected side effects`() { 26 | ParameterisedSideEffectTest(blocking = true) 27 | .`succeeds if posted side effects match expected side effects`() 28 | } 29 | 30 | @Test 31 | fun `NON BLOCKING - succeeds if posted side effects match expected side effects`() { 32 | ParameterisedSideEffectTest(blocking = false) 33 | .`succeeds if posted side effects match expected side effects`() 34 | } 35 | 36 | @Test 37 | fun `BLOCKING - fails if posted side effects do not match expected side effects`() { 38 | ParameterisedSideEffectTest(blocking = true) 39 | .`fails if posted side effects do not match expected side effects`() 40 | } 41 | 42 | @Test 43 | fun `NON BLOCKING - fails if posted side effects do not match expected side effects`() { 44 | ParameterisedSideEffectTest(blocking = false) 45 | .`fails if posted side effects do not match expected side effects`() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava1/src/main/kotlin/com/babylon/orbit2/rxjava1/RxJava1Single.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava1 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import com.babylon.orbit2.syntax.Orbit2Dsl 21 | import com.babylon.orbit2.syntax.strict.Builder 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import rx.Single 25 | 26 | internal class RxJava1Single( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Single 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into a [Single] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Single] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx1Single( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Single 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava1DslPlugin) 46 | return add(RxJava1Single(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/streaming/EmptySubscriptionListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Lightstreamer Srl 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.streaming 18 | 19 | import com.lightstreamer.client.ItemUpdate 20 | import com.lightstreamer.client.Subscription 21 | import com.lightstreamer.client.SubscriptionListener 22 | 23 | /** 24 | * Empty SubscriptionListener 25 | */ 26 | @Suppress("TooManyFunctions") 27 | object EmptySubscriptionListener : SubscriptionListener { 28 | override fun onListenEnd(p0: Subscription) = Unit 29 | 30 | override fun onItemUpdate(p0: ItemUpdate) = Unit 31 | 32 | override fun onSubscription() = Unit 33 | 34 | override fun onEndOfSnapshot(p0: String?, p1: Int) = Unit 35 | 36 | override fun onItemLostUpdates(p0: String?, p1: Int, p2: Int) = Unit 37 | 38 | override fun onSubscriptionError(p0: Int, p1: String?) = Unit 39 | 40 | override fun onClearSnapshot(p0: String?, p1: Int) = Unit 41 | 42 | override fun onCommandSecondLevelSubscriptionError(p0: Int, p1: String?, p2: String?) = Unit 43 | 44 | override fun onUnsubscription() = Unit 45 | 46 | override fun onCommandSecondLevelItemLostUpdates(p0: Int, p1: String) = Unit 47 | 48 | override fun onListenStart(p0: Subscription) = Unit 49 | 50 | override fun onRealMaxFrequency(p0: String?) = Unit 51 | } 52 | -------------------------------------------------------------------------------- /orbit-2-rxjava2/src/main/kotlin/com/babylon/orbit2/rxjava2/RxJava2Maybe.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava2 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.Maybe 25 | 26 | internal class RxJava2Maybe( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Maybe 29 | ) : Operator 30 | 31 | /** 32 | * The maybe transformer flat maps incoming [VolatileContext] for every event into a [Maybe] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Maybe] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx2Maybe( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Maybe 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava2DslPlugin) 46 | return add(RxJava2Maybe(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava1/src/main/kotlin/com/babylon/orbit2/rxjava1/RxJava1Completable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava1 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import rx.Completable 25 | 26 | internal class RxJava1Completable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Completable 29 | ) : Operator 30 | 31 | /** 32 | * The maybe transformer flat maps incoming [VolatileContext] for every event into a [Completable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Completable] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx1Completable( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Completable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava1DslPlugin) 46 | return add(RxJava1Completable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava2/src/main/kotlin/com/babylon/orbit2/rxjava2/RxJava2Single.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava2 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.Single 25 | 26 | internal class RxJava2Single( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Single 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into a [Single] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Single] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx2Single( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Single 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava2DslPlugin) 46 | return add(RxJava2Single(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava3/src/main/kotlin/com/babylon/orbit2/rxjava3/RxJava3Maybe.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava3 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.rxjava3.core.Maybe 25 | 26 | internal class RxJava3Maybe( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Maybe 29 | ) : Operator 30 | 31 | /** 32 | * The maybe transformer flat maps incoming [VolatileContext] for every event into a [Maybe] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Maybe] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx3Maybe( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Maybe 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava3DslPlugin) 46 | return add(RxJava3Maybe(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-coroutines/src/main/kotlin/com/babylon/orbit2/coroutines/TransformSuspend.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.coroutines 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import com.babylon.orbit2.syntax.Orbit2Dsl 21 | import com.babylon.orbit2.syntax.strict.Builder 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import kotlinx.coroutines.Dispatchers 25 | 26 | internal class TransformSuspend( 27 | override val registerIdling: Boolean, 28 | val block: suspend VolatileContext.() -> E2 29 | ) : Operator 30 | 31 | /** 32 | * The suspend transformer maps the incoming state and event into a new event using a suspending 33 | * lambda. 34 | * 35 | * The transformer executes on [Dispatchers.IO] by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the suspending lambda returning a new event given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformSuspend( 42 | registerIdling: Boolean = true, 43 | block: suspend VolatileContext.() -> E2 44 | ): Builder { 45 | OrbitDslPlugins.register(CoroutineDslPlugin) 46 | return add(TransformSuspend(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/list/business/ListViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.list.business 18 | 19 | import androidx.lifecycle.SavedStateHandle 20 | import androidx.lifecycle.ViewModel 21 | import com.babylon.orbit2.ContainerHost 22 | import com.babylon.orbit2.coroutines.transformFlow 23 | import com.babylon.orbit2.sample.stocklist.streaming.stock.StockRepository 24 | import com.babylon.orbit2.syntax.strict.orbit 25 | import com.babylon.orbit2.syntax.strict.reduce 26 | import com.babylon.orbit2.syntax.strict.sideEffect 27 | import com.babylon.orbit2.viewmodel.container 28 | 29 | class ListViewModel( 30 | savedStateHandle: SavedStateHandle, 31 | private val stockRepository: StockRepository 32 | ) : ViewModel(), ContainerHost { 33 | 34 | override val container = container(ListState(), savedStateHandle) { requestStocks() } 35 | 36 | private fun requestStocks(): Unit = orbit { 37 | transformFlow { 38 | stockRepository.stockList() 39 | }.reduce { 40 | state.copy(stocks = event) 41 | } 42 | } 43 | 44 | fun viewMarket(itemName: String) = orbit { 45 | sideEffect { 46 | post(ListSideEffect.NavigateToDetail(itemName)) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /orbit-2-rxjava2/src/main/kotlin/com/babylon/orbit2/rxjava2/RxJava2Completable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava2 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.Completable 25 | 26 | internal class RxJava2Completable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Completable 29 | ) : Operator 30 | 31 | /** 32 | * The maybe transformer flat maps incoming [VolatileContext] for every event into a [Completable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Completable] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx2Completable( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Completable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava2DslPlugin) 46 | return add(RxJava2Completable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava3/src/main/kotlin/com/babylon/orbit2/rxjava3/RxJava3Single.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava3 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.rxjava3.core.Single 25 | 26 | internal class RxJava3Single( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Single 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into a [Single] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Single] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx3Single( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Single 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava3DslPlugin) 46 | return add(RxJava3Single(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava1/src/main/kotlin/com/babylon/orbit2/rxjava1/RxJava1Observable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava1 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import rx.Observable 25 | 26 | internal class RxJava1Observable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Observable 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into an [Observable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: false 38 | * @param block the lambda returning a new observable of events given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx1Observable( 42 | registerIdling: Boolean = false, 43 | block: VolatileContext.() -> Observable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava1DslPlugin) 46 | return add(RxJava1Observable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava3/src/main/kotlin/com/babylon/orbit2/rxjava3/RxJava3Completable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava3 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.rxjava3.core.Completable 25 | 26 | internal class RxJava3Completable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Completable 29 | ) : Operator 30 | 31 | /** 32 | * The maybe transformer flat maps incoming [VolatileContext] for every event into a [Completable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: true 38 | * @param block the lambda returning a new [Completable] given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx3Completable( 42 | registerIdling: Boolean = true, 43 | block: VolatileContext.() -> Completable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava3DslPlugin) 46 | return add(RxJava3Completable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-coroutines/src/main/kotlin/com/babylon/orbit2/coroutines/TransformFlow.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.coroutines 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import kotlinx.coroutines.Dispatchers 25 | import kotlinx.coroutines.flow.Flow 26 | 27 | internal class TransformFlow( 28 | override val registerIdling: Boolean, 29 | val block: suspend VolatileContext.() -> Flow 30 | ) : Operator 31 | 32 | /** 33 | * The flow transformer flat maps incoming [VolatileContext] for every event into coroutine flows. 34 | * 35 | * The transformer executes on [Dispatchers.IO] by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: false 38 | * @param block the suspending lambda returning a new flow of events given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformFlow( 42 | registerIdling: Boolean = false, 43 | block: suspend VolatileContext.() -> Flow 44 | ): Builder { 45 | OrbitDslPlugins.register(CoroutineDslPlugin) 46 | return add(TransformFlow(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-rxjava2/src/main/kotlin/com/babylon/orbit2/rxjava2/RxJava2Observable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava2 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.Observable 25 | 26 | internal class RxJava2Observable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Observable 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into an [Observable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: false 38 | * @param block the lambda returning a new observable of events given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx2Observable( 42 | registerIdling: Boolean = false, 43 | block: VolatileContext.() -> Observable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava2DslPlugin) 46 | return add(RxJava2Observable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /orbit-2-viewmodel/src/test/koltin/com/babylon/orbit2/viewmodel/AndroidIdlingResourceRobolectricTest.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.viewmodel 2 | 3 | import androidx.test.espresso.Espresso 4 | import androidx.test.espresso.idling.CountingIdlingResource 5 | import com.babylon.orbit2.Container 6 | import com.babylon.orbit2.container 7 | import io.kotest.matchers.shouldBe 8 | import kotlinx.coroutines.CoroutineScope 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.cancel 11 | import org.junit.After 12 | import org.junit.Test 13 | import org.junit.runner.RunWith 14 | import org.robolectric.RobolectricTestRunner 15 | import org.robolectric.annotation.Config 16 | 17 | @RunWith(RobolectricTestRunner::class) 18 | @Config(manifest = Config.NONE, sdk = [28]) 19 | class AndroidIdlingResourceRobolectricTest { 20 | 21 | private val scope = CoroutineScope(Dispatchers.Unconfined) 22 | 23 | @After 24 | fun after() { 25 | scope.cancel() 26 | } 27 | 28 | @Test 29 | fun `idling resources have unique names`() { 30 | scope.container( 31 | initialState = TestState(0), 32 | settings = Container.Settings(idlingRegistry = AndroidIdlingResource()) 33 | ) 34 | 35 | scope.container( 36 | initialState = TestState(0), 37 | settings = Container.Settings(idlingRegistry = AndroidIdlingResource()) 38 | ) 39 | 40 | forceIdlingResourceSync() 41 | 42 | @Suppress("DEPRECATION") 43 | Espresso.getIdlingResources().size.shouldBe(2) 44 | } 45 | 46 | /** 47 | * Force IdlingRegistry to be synced into Espresso.baseRegistry 48 | */ 49 | private fun forceIdlingResourceSync() { 50 | CountingIdlingResource("bob").apply { 51 | @Suppress("DEPRECATION") 52 | Espresso.registerIdlingResources(this) 53 | @Suppress("DEPRECATION") 54 | Espresso.unregisterIdlingResources(this) 55 | } 56 | } 57 | 58 | data class TestState(val value: Int) 59 | } 60 | -------------------------------------------------------------------------------- /orbit-2-rxjava3/src/main/kotlin/com/babylon/orbit2/rxjava3/RxJava3Observable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.rxjava3 18 | 19 | import com.babylon.orbit2.syntax.strict.Builder 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 23 | import com.babylon.orbit2.syntax.strict.VolatileContext 24 | import io.reactivex.rxjava3.core.Observable 25 | 26 | internal class RxJava3Observable( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> Observable 29 | ) : Operator 30 | 31 | /** 32 | * The observable transformer flat maps incoming [VolatileContext] for every event into an [Observable] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: false 38 | * @param block the lambda returning a new observable of events given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | public fun Builder.transformRx3Observable( 42 | registerIdling: Boolean = false, 43 | block: VolatileContext.() -> Observable 44 | ): Builder { 45 | OrbitDslPlugins.register(RxJava3DslPlugin) 46 | return add(RxJava3Observable(registerIdling, block)) 47 | } 48 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/StockListApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist 18 | 19 | import android.app.Application 20 | import androidx.lifecycle.SavedStateHandle 21 | import com.babylon.orbit2.sample.stocklist.detail.business.DetailViewModel 22 | import com.babylon.orbit2.sample.stocklist.list.business.ListViewModel 23 | import com.babylon.orbit2.sample.stocklist.streaming.StreamingClient 24 | import com.babylon.orbit2.sample.stocklist.streaming.stock.StockRepository 25 | import org.koin.android.ext.koin.androidContext 26 | import org.koin.androidx.viewmodel.dsl.viewModel 27 | import org.koin.core.context.startKoin 28 | import org.koin.dsl.module 29 | 30 | @Suppress("unused") 31 | class StockListApplication : Application() { 32 | 33 | override fun onCreate() { 34 | super.onCreate() 35 | 36 | startKoin { 37 | androidContext(this@StockListApplication) 38 | modules(listOf(mainModule)) 39 | } 40 | } 41 | 42 | private val mainModule = module { 43 | single { StreamingClient() } 44 | single { StockRepository(get()) } 45 | 46 | viewModel { (savedStateHandle: SavedStateHandle) -> ListViewModel(savedStateHandle, get()) } 47 | viewModel { (savedStateHandle: SavedStateHandle, itemName: String) -> DetailViewModel(savedStateHandle, itemName, get()) } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /orbit-2-livedata/src/main/kotlin/com/babylon/orbit2/livedata/LiveDataDslPlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.livedata 18 | 19 | import androidx.lifecycle.asFlow 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 22 | import com.babylon.orbit2.syntax.strict.VolatileContext 23 | import com.babylon.orbit2.idling.withIdlingFlow 24 | import kotlinx.coroutines.flow.Flow 25 | import kotlinx.coroutines.flow.flatMapConcat 26 | import kotlinx.coroutines.flow.flowOn 27 | 28 | /** 29 | * Orbit plugin providing LiveData DSL operators: 30 | * 31 | * * [transformLiveData] 32 | */ 33 | object LiveDataDslPlugin : OrbitDslPlugin { 34 | 35 | @Suppress("UNCHECKED_CAST", "EXPERIMENTAL_API_USAGE") 36 | override fun apply( 37 | containerContext: OrbitDslPlugin.ContainerContext, 38 | flow: Flow, 39 | operator: Operator, 40 | createContext: (event: E) -> VolatileContext 41 | ): Flow { 42 | return when (operator) { 43 | is LiveDataOperator<*, *, *> -> flow.flatMapConcat { 44 | containerContext.withIdlingFlow(operator as LiveDataOperator) { 45 | createContext(it).block().asFlow().flowOn(containerContext.settings.backgroundDispatcher) 46 | } 47 | } 48 | else -> flow 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/syntax/strict/Builder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.syntax.strict 18 | 19 | import com.babylon.orbit2.syntax.Operator 20 | import com.babylon.orbit2.syntax.Orbit2Dsl 21 | import kotlinx.coroutines.flow.Flow 22 | import kotlinx.coroutines.flow.flowOf 23 | 24 | @Orbit2Dsl 25 | public class Builder(private val stack: List> = emptyList()) { 26 | 27 | public fun add(operator: Operator): Builder { 28 | return Builder(stack + operator) 29 | } 30 | 31 | @Suppress("UNCHECKED_CAST") 32 | internal fun build( 33 | pluginContext: OrbitDslPlugin.ContainerContext 34 | ): Flow { 35 | return stack.fold(flowOf(Unit)) { flow: Flow, operator: Operator -> 36 | OrbitDslPlugins.plugins.fold(flow) { flow2: Flow, plugin: OrbitDslPlugin -> 37 | plugin.apply( 38 | pluginContext, 39 | flow2, 40 | operator as Operator 41 | ) { 42 | object : VolatileContext { 43 | override val state = volatileState() 44 | override val event = it 45 | override fun volatileState() = pluginContext.state 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /orbit-2-livedata/src/main/kotlin/com/babylon/orbit2/livedata/LiveDataOperator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.livedata 18 | 19 | import androidx.lifecycle.LiveData 20 | import com.babylon.orbit2.syntax.Operator 21 | import com.babylon.orbit2.syntax.Orbit2Dsl 22 | import com.babylon.orbit2.syntax.strict.Builder 23 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugins 24 | import com.babylon.orbit2.syntax.strict.VolatileContext 25 | 26 | internal class LiveDataOperator( 27 | override val registerIdling: Boolean, 28 | val block: VolatileContext.() -> LiveData 29 | ) : Operator 30 | 31 | /** 32 | * The transformer flat maps incoming [VolatileContext] for every event into a [LiveData] of 33 | * another type. 34 | * 35 | * The transformer executes on an `IO` dispatcher by default. 36 | * 37 | * @param registerIdling When true tracks the block's idling state, default: false 38 | * @param block the lambda returning a new observable of events given the current state and event 39 | */ 40 | @Orbit2Dsl 41 | fun Builder.transformLiveData( 42 | registerIdling: Boolean = false, 43 | block: VolatileContext.() -> LiveData 44 | ): Builder { 45 | OrbitDslPlugins.register(LiveDataDslPlugin) 46 | return add( 47 | LiveDataOperator( 48 | registerIdling, 49 | block 50 | ) 51 | ) 52 | } 53 | -------------------------------------------------------------------------------- /orbit-2-test/src/main/kotlin/com/babylon/orbit2/TestContainer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2 18 | 19 | import com.babylon.orbit2.internal.RealContainer 20 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 21 | import kotlinx.atomicfu.atomic 22 | import kotlinx.coroutines.CoroutineScope 23 | import kotlinx.coroutines.Dispatchers 24 | import kotlinx.coroutines.runBlocking 25 | 26 | internal class TestContainer( 27 | initialState: STATE, 28 | private val isolateFlow: Boolean, 29 | private val blocking: Boolean 30 | ) : RealContainer( 31 | initialState = initialState, 32 | parentScope = CoroutineScope(Dispatchers.Unconfined), 33 | settings = Container.Settings( 34 | orbitDispatcher = 35 | @Suppress("EXPERIMENTAL_API_USAGE") if (blocking) Dispatchers.Unconfined else Dispatchers.Default, 36 | backgroundDispatcher = Dispatchers.Unconfined 37 | ) 38 | ) { 39 | private val dispatched = atomic(0) 40 | 41 | override fun orbit(orbitFlow: suspend OrbitDslPlugin.ContainerContext.() -> Unit) { 42 | if (!isolateFlow || dispatched.compareAndSet(0, 1)) { 43 | if (blocking) { 44 | runBlocking { 45 | orbitFlow(pluginContext) 46 | } 47 | } else { 48 | super.orbit(orbitFlow) 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/CoroutineScopeExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2 18 | 19 | import com.babylon.orbit2.Container.Settings 20 | import com.babylon.orbit2.internal.LazyCreateContainerDecorator 21 | import com.babylon.orbit2.internal.RealContainer 22 | import kotlinx.coroutines.CoroutineScope 23 | 24 | /** 25 | * Helps create a concrete container in a standard way. 26 | * 27 | * @param initialState The initial state of the container. 28 | * @param settings The [Settings] to set the container up with. 29 | * @param onCreate The lambda to execute when the container is created. By default it is 30 | * executed in a lazy manner when the container is first interacted with in any way. 31 | * @return A [Container] implementation 32 | */ 33 | public fun CoroutineScope.container( 34 | initialState: STATE, 35 | settings: Settings = Settings(), 36 | onCreate: ((state: STATE) -> Unit)? = null 37 | ): Container = 38 | if (onCreate == null) { 39 | RealContainer( 40 | initialState = initialState, 41 | settings = settings, 42 | parentScope = this 43 | ) 44 | } else { 45 | LazyCreateContainerDecorator( 46 | RealContainer( 47 | initialState = initialState, 48 | settings = settings, 49 | parentScope = this 50 | ), 51 | onCreate 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /orbit-2-core/src/main/kotlin/com/babylon/orbit2/internal/LazyCreateContainerDecorator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.internal 18 | 19 | import com.babylon.orbit2.Container 20 | import com.babylon.orbit2.ContainerDecorator 21 | import com.babylon.orbit2.syntax.strict.OrbitDslPlugin 22 | import kotlinx.atomicfu.atomic 23 | import kotlinx.coroutines.flow.Flow 24 | import kotlinx.coroutines.flow.emitAll 25 | import kotlinx.coroutines.flow.flow 26 | 27 | public class LazyCreateContainerDecorator( 28 | override val actual: Container, 29 | public val onCreate: (state: STATE) -> Unit 30 | ) : ContainerDecorator { 31 | private val created = atomic(0) 32 | 33 | override val currentState: STATE 34 | get() = actual.currentState 35 | 36 | override val stateFlow: Flow 37 | get() = flow { 38 | runOnCreate() 39 | emitAll(actual.stateFlow) 40 | } 41 | 42 | override val sideEffectFlow: Flow 43 | get() = flow { 44 | runOnCreate() 45 | emitAll(actual.sideEffectFlow) 46 | } 47 | 48 | private fun runOnCreate() { 49 | if (created.compareAndSet(0, 1)) { 50 | onCreate(actual.currentState) 51 | } 52 | } 53 | 54 | override fun orbit(orbitFlow: suspend OrbitDslPlugin.ContainerContext.() -> Unit) { 55 | runOnCreate().also { actual.orbit(orbitFlow) } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postlist/viewmodel/PostListViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postlist.viewmodel 18 | 19 | import androidx.lifecycle.SavedStateHandle 20 | import androidx.lifecycle.ViewModel 21 | import com.babylon.orbit2.ContainerHost 22 | import com.babylon.orbit2.sample.posts.app.common.NavigationEvent 23 | import com.babylon.orbit2.sample.posts.domain.repositories.PostOverview 24 | import com.babylon.orbit2.sample.posts.domain.repositories.PostRepository 25 | import com.babylon.orbit2.syntax.simple.intent 26 | import com.babylon.orbit2.syntax.simple.postSideEffect 27 | import com.babylon.orbit2.syntax.simple.reduce 28 | import com.babylon.orbit2.viewmodel.container 29 | 30 | class PostListViewModel( 31 | savedStateHandle: SavedStateHandle, 32 | private val postRepository: PostRepository 33 | ) : ViewModel(), ContainerHost { 34 | 35 | override val container = container(PostListState(), savedStateHandle) { 36 | if (it.overviews.isEmpty()) { 37 | loadOverviews() 38 | } 39 | } 40 | 41 | private fun loadOverviews() = intent { 42 | val overviews = postRepository.getOverviews() 43 | 44 | reduce { 45 | state.copy(overviews = overviews) 46 | } 47 | } 48 | 49 | fun onPostClicked(post: PostOverview) = intent { 50 | postSideEffect(OpenPostNavigationEvent(post)) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/test/kotlin/com/babylon/orbit2/sample/calculator/livedata/TestLiveDataObserver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.calculator.livedata 18 | 19 | import androidx.lifecycle.LifecycleOwner 20 | import androidx.lifecycle.LiveData 21 | import androidx.lifecycle.Observer 22 | 23 | fun LiveData.test(lifecycleOwner: LifecycleOwner) = 24 | TestLiveDataObserver(lifecycleOwner, this) 25 | 26 | class TestLiveDataObserver(lifecycleOwner: LifecycleOwner, private val liveData: LiveData) { 27 | private val _values = mutableListOf() 28 | private val observer = Observer { 29 | _values.add(it) 30 | } 31 | val values: List 32 | get() = _values 33 | 34 | init { 35 | liveData.observe(lifecycleOwner, observer) 36 | } 37 | 38 | fun awaitCount(count: Int, timeout: Long = 5000L) { 39 | val start = System.currentTimeMillis() 40 | while (values.count() < count) { 41 | if (System.currentTimeMillis() - start > timeout) { 42 | break 43 | } 44 | Thread.sleep(10) 45 | } 46 | } 47 | 48 | fun awaitIdle(timeout: Long = 10L) { 49 | var currentCount = values.count() 50 | 51 | while (true) { 52 | Thread.sleep(timeout) 53 | 54 | if (values.count() == currentCount) { 55 | break 56 | } 57 | 58 | currentCount = values.count() 59 | } 60 | } 61 | 62 | fun close(): Unit = liveData.removeObserver(observer) 63 | } 64 | -------------------------------------------------------------------------------- /samples/orbit-2-stocklist/src/main/kotlin/com/babylon/orbit2/sample/stocklist/streaming/StreamingClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.stocklist.streaming 18 | 19 | import androidx.lifecycle.DefaultLifecycleObserver 20 | import androidx.lifecycle.LifecycleOwner 21 | import com.lightstreamer.client.LightstreamerClient 22 | import com.lightstreamer.client.Subscription 23 | import kotlin.concurrent.thread 24 | 25 | class StreamingClient : DefaultLifecycleObserver { 26 | private var connectionWish = false 27 | 28 | private val lsClient = LightstreamerClient( 29 | "http://push.lightstreamer.com:80", 30 | "DEMO" 31 | ).apply { 32 | connect() 33 | } 34 | 35 | override fun onStart(owner: LifecycleOwner) { 36 | synchronized(lsClient) { 37 | connectionWish = true 38 | lsClient.connect() 39 | } 40 | } 41 | 42 | override fun onStop(owner: LifecycleOwner) { 43 | synchronized(lsClient) { 44 | connectionWish = false 45 | 46 | thread { 47 | @Suppress("MagicNumber") 48 | Thread.sleep(5000) 49 | synchronized(lsClient) { 50 | if (!connectionWish) { 51 | lsClient.disconnect() 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | fun addSubscription(sub: Subscription) { 59 | lsClient.subscribe(sub) 60 | } 61 | 62 | fun removeSubscription(sub: Subscription) { 63 | lsClient.unsubscribe(sub) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /samples/orbit-2-posts/src/main/kotlin/com/babylon/orbit2/sample/posts/app/features/postdetails/viewmodel/PostDetailsViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Babylon Partners Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.babylon.orbit2.sample.posts.app.features.postdetails.viewmodel 18 | 19 | import androidx.lifecycle.SavedStateHandle 20 | import androidx.lifecycle.ViewModel 21 | import com.babylon.orbit2.ContainerHost 22 | import com.babylon.orbit2.sample.posts.domain.repositories.PostOverview 23 | import com.babylon.orbit2.sample.posts.domain.repositories.PostRepository 24 | import com.babylon.orbit2.sample.posts.domain.repositories.Status 25 | import com.babylon.orbit2.syntax.simple.intent 26 | import com.babylon.orbit2.syntax.simple.reduce 27 | import com.babylon.orbit2.viewmodel.container 28 | 29 | class PostDetailsViewModel( 30 | savedStateHandle: SavedStateHandle, 31 | private val postRepository: PostRepository, 32 | private val postOverview: PostOverview 33 | ) : ViewModel(), ContainerHost { 34 | 35 | override val container = container(PostDetailState.NoDetailsAvailable(postOverview), savedStateHandle) { 36 | if (it !is PostDetailState.Details) { 37 | loadDetails() 38 | } 39 | } 40 | 41 | private fun loadDetails() = intent { 42 | val status = postRepository.getDetail(postOverview.id) 43 | 44 | reduce { 45 | when (status) { 46 | is Status.Success -> PostDetailState.Details(state.postOverview, status.data) 47 | is Status.Failure -> PostDetailState.NoDetailsAvailable(state.postOverview) 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /orbit-2-viewmodel/src/main/kotlin/com/babylon/orbit2/viewmodel/AndroidIdlingResource.kt: -------------------------------------------------------------------------------- 1 | package com.babylon.orbit2.viewmodel 2 | 3 | import androidx.test.espresso.IdlingRegistry 4 | import androidx.test.espresso.IdlingResource.ResourceCallback 5 | import com.babylon.orbit2.idling.IdlingResource 6 | import kotlinx.coroutines.GlobalScope 7 | import kotlinx.coroutines.Job 8 | import kotlinx.coroutines.delay 9 | import kotlinx.coroutines.launch 10 | import java.util.UUID 11 | import java.util.concurrent.atomic.AtomicBoolean 12 | import java.util.concurrent.atomic.AtomicInteger 13 | import java.util.concurrent.atomic.AtomicReference 14 | 15 | class AndroidIdlingResource : IdlingResource { 16 | 17 | private val counter: AtomicInteger = AtomicInteger(0) 18 | private val idle = AtomicBoolean(true) 19 | 20 | private val job = AtomicReference() 21 | 22 | private var resourceCallback: ResourceCallback? = null 23 | 24 | private val espressoIdlingResource = object : androidx.test.espresso.IdlingResource { 25 | private val uniqueId = UUID.randomUUID() 26 | override fun getName() = "orbit-mvi-$uniqueId" 27 | 28 | override fun isIdleNow() = idle.get() 29 | 30 | override fun registerIdleTransitionCallback(resourceCallback: ResourceCallback?) { 31 | this@AndroidIdlingResource.resourceCallback = resourceCallback 32 | } 33 | } 34 | 35 | init { 36 | IdlingRegistry.getInstance().register(espressoIdlingResource) 37 | } 38 | 39 | override fun increment() { 40 | if (counter.getAndIncrement() == 0) { 41 | job.get()?.cancel() 42 | } 43 | idle.set(false) 44 | } 45 | 46 | override fun decrement() { 47 | if (counter.decrementAndGet() == 0) { 48 | job.getAndSet( 49 | GlobalScope.launch { 50 | delay(MILLIS_BEFORE_IDLE) 51 | idle.set(true) 52 | resourceCallback?.onTransitionToIdle() 53 | } 54 | )?.cancel() 55 | } 56 | } 57 | 58 | override fun close() { 59 | IdlingRegistry.getInstance().unregister(espressoIdlingResource) 60 | } 61 | 62 | companion object { 63 | private const val MILLIS_BEFORE_IDLE = 100L 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /samples/orbit-2-calculator/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 39 | 40 | 43 | 44 | 47 | 48 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /orbit-2-rxjava1/README.md: -------------------------------------------------------------------------------- 1 | # Orbit 2 RxJava1 plugin 2 | 3 | - [Orbit 2 RxJava1 plugin](#orbit-2-rxjava1-plugin) 4 | - [transformRx1Observable](#transformrx1observable) 5 | - [transformRx1Single](#transformrx1single) 6 | - [transformRx1Completable](#transformrx1completable) 7 | 8 | The RxJava1 plugin provides RxJava 1 operators. 9 | 10 | ```kotlin 11 | implementation("com.babylon.orbit2:orbit-rxjava1:") 12 | ``` 13 | 14 | ## transformRx1Observable 15 | 16 | ``` kotlin 17 | fun subscribeToLocationUpdates(): Observable { ... } 18 | 19 | class ExampleViewModel : ContainerHost { 20 | ... 21 | 22 | fun startLocationTracking() = orbit { 23 | transformRx1Observable { subscribeToLocationUpdates() } 24 | .reduce { state.copy(currentLocation = event) } 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | You can use this operator to subscribe to a hot or cold [Observable](http://reactivex.io/documentation/observable.html). 31 | This operator acts similar to [flatMap](https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables#flatmap). 32 | 33 | ## transformRx1Single 34 | 35 | ``` kotlin 36 | fun apiCall(): Single { ... } 37 | fun anotherApiCall(param: SomeResult): Single { ... } 38 | 39 | class ExampleViewModel : ContainerHost { 40 | ... 41 | 42 | fun example() = orbit { 43 | transformRx1Single { apiCall() } 44 | .transformRx1Single { anotherApiCall(event) } // "event" is the result of the first api call 45 | } 46 | } 47 | } 48 | ``` 49 | 50 | You can use this operator to subscribe to an RxJava 1 [Single](http://reactivex.io/documentation/single.html). 51 | This operator acts similar to [flatMapSingle](https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables#flatmapsingle). 52 | 53 | ## transformRx1Completable 54 | 55 | ``` kotlin 56 | fun doSomeWork(): Completable { ... } 57 | 58 | class ExampleViewModel : ContainerHost { 59 | ... 60 | 61 | fun example() = orbit { 62 | transformRx1Completable { doSomeWork() } 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | You can use this operator to subscribe to an RxJava 1 `Completable`. 69 | This operator acts similar to [flatMapCompletable](https://github.com/ReactiveX/RxJava/wiki/Transforming-Observables#flatmapcompletable). 70 | --------------------------------------------------------------------------------