Skip to content

Commit

Permalink
feat: ScreenModel integrated with Coroutines, RxJava, Koin, Kodein
Browse files Browse the repository at this point in the history
  • Loading branch information
adrielcafe committed Sep 3, 2021
1 parent 2fd7081 commit ecd604a
Show file tree
Hide file tree
Showing 68 changed files with 883 additions and 274 deletions.
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ Voyager is a lightweight and complete navigation library built for, and seamless
Create scalable Single-Activity apps powered by a [pragmatic API](https://voyager.adriel.cafe/navigation/fundamentals).

```kotlin
class HomeScreenModel : ScreenModel {
// ...
}

class HomeScreen : Screen {

@Composable
override fun Content() {
// Your awesome UI goes here
val screenModel = rememberScreenModel<HomeScreenModel>()
// ...
}
}

Expand All @@ -41,13 +46,16 @@ Turn on the Warp Drive and enjoy the trek 🖖
See the [project website](https://voyager.adriel.cafe) for documentation and APIs.

### Features
- [Linear navigation](https://voyager.adriel.cafe/navigation/fundamentals)
- [BottomSheet navigation](https://voyager.adriel.cafe/navigation/bottomsheet-navigation)
- [Tab navigation](https://voyager.adriel.cafe/navigation/tab-navigation) like [Youtube app](https://play.google.com/store/apps/details?id=com.google.android.youtube)
- [Nested navigation](https://voyager.adriel.cafe/navigation/nested-navigation) if you need to manage multiple stacks
- [State restoration](https://voyager.adriel.cafe/state-restoration) after Activity recreation
- [Nested navigation](https://voyager.adriel.cafe/navigation/nested-navigation) (multiple stacks, parent navigation)
- [ScreenModel](https://voyager.adriel.cafe/screenmodel/fundamentals) (a.k.a ViewModel) integrated with [Koin](https://voyager.adriel.cafe/screenmodel/koin-integration), [Kodein](https://voyager.adriel.cafe/screenmodel/kodein-integration), [Coroutines](https://voyager.adriel.cafe/screenmodel/coroutines-integration), [RxJava](https://voyager.adriel.cafe/screenmodel/rxjava-integration)
- [Android ViewModel](https://voyager.adriel.cafe/android-viewmodel) integration
- Type-safe [multi-module navigation](https://voyager.adriel.cafe/navigation/multi-module-navigation)
- State-aware [Stack API](https://voyager.adriel.cafe/stack-api)
- Built-in [transitions](https://voyager.adriel.cafe/transitions)
- [State restoration](https://voyager.adriel.cafe/state-restoration) after Activity recreation
- [Lifecycle](https://voyager.adriel.cafe/lifecycle) callbacks
- [Back press](https://voyager.adriel.cafe/back-press) handling
- [Deep linking](https://voyager.adriel.cafe/deep-links) support
Expand All @@ -56,10 +64,10 @@ See the [project website](https://voyager.adriel.cafe) for documentation and API
- [Compose for Desktop](https://github.com/JetBrains/compose-jb) support

### Samples
| [Stack API](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/stateStack) | [AndroidX ViewModel](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation) | [Basic nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation) |
|------------|----------|-------------|
| ![navigation-stack](https://user-images.githubusercontent.com/2512298/126323192-9b6349fe-7b96-4acf-b62e-c75165d909e1.gif) | ![navigation-androidx](https://user-images.githubusercontent.com/2512298/130377801-c350b4f5-bcca-4d28-9403-0d9d4c1e99f7.gif) | ![navigation-basic](https://user-images.githubusercontent.com/2512298/126323165-47760eec-2ba2-48ee-8e3a-841d50098d33.gif) |
| [Stack API](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/stateStack) | [Android ViewModel](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/androidViewModel) | [ScreenModel](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/screenModel) | [Basic nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation) |
|----------|----------|----------|----------|
| ![navigation-stack](https://user-images.githubusercontent.com/2512298/126323192-9b6349fe-7b96-4acf-b62e-c75165d909e1.gif) | ![navigation-android-viewmodel](https://user-images.githubusercontent.com/2512298/130377801-c350b4f5-bcca-4d28-9403-0d9d4c1e99f7.gif) | ![navigation-screenmodel](https://user-images.githubusercontent.com/2512298/131770829-fa85cb19-cc76-4fbf-9bdc-165997d5349d.gif) | ![navigation-basic](https://user-images.githubusercontent.com/2512298/126323165-47760eec-2ba2-48ee-8e3a-841d50098d33.gif) |

| [BottomSheet nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation) | [Tab nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation) | [Multi-module nav.](https://github.com/adrielcafe/voyager/tree/main/sample-multi-module) | [Nested nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/nestedNavigation) |
|------------|------------|----------|-------------|
|----------|----------|----------|----------|
| ![navigation-bottom-sheet](https://user-images.githubusercontent.com/2512298/131191122-18025192-ce4d-4659-9afa-aacfdb488796.gif) | ![navigation-tab](https://user-images.githubusercontent.com/2512298/126323588-2f970953-0adb-47f8-b2fb-91c5854656bd.gif) | ![navigation-multi-module](https://user-images.githubusercontent.com/2512298/130662717-c15caf88-350e-42a0-837c-3453805b68f2.gif) | ![navigation-nested](https://user-images.githubusercontent.com/2512298/126323027-a2633aef-9402-4df8-9384-45935d7986cf.gif) |
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ kotlin.code.style=official

# Maven
GROUP=cafe.adriel.voyager
VERSION_NAME=1.0.0-beta09
VERSION_NAME=1.0.0-beta10

POM_DESCRIPTION=A pragmatic navigation library for Jetpack Compose
POM_INCEPTION_YEAR=2021
Expand Down
11 changes: 8 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
[versions]
plugin-android = "7.0.0"
plugin-android = "7.0.2"
plugin-ktlint = "10.1.0"
plugin-maven = "0.17.0"

kotlin = "1.5.21"
kotlin = "1.5.30"
kodein = "7.7.0"
koin = "3.1.2"
leakCanary = "2.7"
appCompat = "1.3.1"
lifecycle = "2.4.0-alpha03"
compose = "1.1.0-alpha02"
compose = "1.1.0-alpha03"
composeActivity = "1.3.1"
composeViewModel = "1.0.0-alpha07"

Expand All @@ -19,10 +21,13 @@ plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.
plugin-ktlint = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "plugin-ktlint" }
plugin-maven = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "plugin-maven" }

leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" }
kodein = { module = "org.kodein.di:kodein-di-framework-compose", version.ref = "kodein" }
koin = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
appCompat = { module = "androidx.appcompat:appcompat", version.ref = "appCompat" }
lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
lifecycle-savedState = { module = "androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "lifecycle" }
compose-rxjava = { module = "androidx.compose.runtime:runtime-rxjava3", version.ref = "compose" }
compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compose" }
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }
compose-runtimeSaveable = { module = "androidx.compose.runtime:runtime-saveable", version.ref = "compose" }
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sun Jun 06 10:15:22 BRT 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
2 changes: 2 additions & 0 deletions sample-multi-module/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ dependencies {
implementation libs.compose.runtime
implementation libs.compose.activity
implementation libs.compose.material

debugImplementation libs.leakCanary
}
7 changes: 7 additions & 0 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ dependencies {
implementation projects.voyagerBottomSheetNavigator
implementation projects.voyagerTransitions
implementation projects.voyagerAndroidx
implementation projects.voyagerKodein
implementation projects.voyagerKoin
implementation projects.voyagerRxjava

implementation libs.kodein
implementation libs.koin
implementation libs.appCompat
implementation libs.compose.rxjava
implementation libs.compose.viewModel
implementation libs.compose.compiler
implementation libs.compose.runtime
implementation libs.compose.activity
implementation libs.compose.material
implementation libs.compose.materialIcons

debugImplementation libs.leakCanary
}
6 changes: 5 additions & 1 deletion sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
<activity android:name=".basicNavigation.BasicNavigationActivity"/>
<activity android:name=".tabNavigation.TabNavigationActivity"/>
<activity android:name=".nestedNavigation.NestedNavigationActivity"/>
<activity android:name=".androidNavigation.AndroidNavigationActivity"/>
<activity android:name=".screenModel.ScreenModelActivity"/>
<activity android:name=".androidViewModel.AndroidViewModelActivity"/>
<activity android:name=".bottomSheetNavigation.BottomSheetNavigationActivity"/>
<activity android:name=".rxjavaIntegration.RxJavaIntegrationActivity"/>
<activity android:name=".kodeinIntegration.KodeinIntegrationActivity"/>
<activity android:name=".koinIntegration.KoinIntegrationActivity"/>
</application>

</manifest>
22 changes: 17 additions & 5 deletions sample/src/main/java/cafe/adriel/voyager/sample/App.kt
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
package cafe.adriel.voyager.sample

import android.app.Application
import cafe.adriel.voyager.sample.androidNavigation.DetailsViewModel
import cafe.adriel.voyager.sample.androidNavigation.ListViewModel
import cafe.adriel.voyager.sample.androidViewModel.AndroidDetailsViewModel
import cafe.adriel.voyager.sample.androidViewModel.AndroidListViewModel
import cafe.adriel.voyager.sample.kodeinIntegration.KodeinScreenModel
import cafe.adriel.voyager.sample.koinIntegration.KoinScreenModel
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.bindProvider
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.context.startKoin
import org.koin.dsl.factory
import org.koin.dsl.module

class App : Application() {
class App : Application(), DIAware {

override val di by DI.lazy {
bindProvider { KodeinScreenModel() }
}

override fun onCreate() {
super.onCreate()
startKoin {
modules(
module {
factory<KoinScreenModel>()

viewModel {
ListViewModel(handle = get())
AndroidListViewModel(handle = get())
}
viewModel { parameters ->
DetailsViewModel(index = parameters.get())
AndroidDetailsViewModel(index = parameters.get())
}
}
)
Expand Down
41 changes: 21 additions & 20 deletions sample/src/main/java/cafe/adriel/voyager/sample/SampleActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.sample.androidNavigation.AndroidNavigationActivity
import cafe.adriel.voyager.sample.androidViewModel.AndroidViewModelActivity
import cafe.adriel.voyager.sample.basicNavigation.BasicNavigationActivity
import cafe.adriel.voyager.sample.bottomSheetNavigation.BottomSheetNavigationActivity
import cafe.adriel.voyager.sample.kodeinIntegration.KodeinIntegrationActivity
import cafe.adriel.voyager.sample.koinIntegration.KoinIntegrationActivity
import cafe.adriel.voyager.sample.nestedNavigation.NestedNavigationActivity
import cafe.adriel.voyager.sample.rxjavaIntegration.RxJavaIntegrationActivity
import cafe.adriel.voyager.sample.screenModel.ScreenModelActivity
import cafe.adriel.voyager.sample.stateStack.StateStackActivity
import cafe.adriel.voyager.sample.tabNavigation.TabNavigationActivity

Expand All @@ -38,24 +40,23 @@ class SampleActivity : ComponentActivity() {

@Composable
fun Content() {
Column(
LazyColumn(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(24.dp)
modifier = Modifier.fillMaxSize().padding(24.dp)
) {
StartSampleButton<StateStackActivity>("SnapshotStateStack")
Spacer(modifier = Modifier.height(24.dp))
StartSampleButton<BasicNavigationActivity>("Basic Navigation")
Spacer(modifier = Modifier.height(24.dp))
StartSampleButton<TabNavigationActivity>("Tab Navigation")
Spacer(modifier = Modifier.height(24.dp))
StartSampleButton<BottomSheetNavigationActivity>("BottomSheet Navigation")
Spacer(modifier = Modifier.height(24.dp))
StartSampleButton<AndroidNavigationActivity>("Android Navigation")
Spacer(modifier = Modifier.height(24.dp))
StartSampleButton<NestedNavigationActivity>("Nested Navigation")
item {
StartSampleButton<StateStackActivity>("SnapshotStateStack")
StartSampleButton<BasicNavigationActivity>("Basic Navigation")
StartSampleButton<TabNavigationActivity>("Tab Navigation")
StartSampleButton<BottomSheetNavigationActivity>("BottomSheet Navigation")
StartSampleButton<NestedNavigationActivity>("Nested Navigation")
StartSampleButton<AndroidViewModelActivity>("Android ViewModel")
StartSampleButton<ScreenModelActivity>("ScreenModel")
StartSampleButton<KoinIntegrationActivity>("Koin Integration")
StartSampleButton<KodeinIntegrationActivity>("Kodein Integration")
StartSampleButton<RxJavaIntegrationActivity>("RxJava Integration")
}
}
}

Expand All @@ -65,7 +66,7 @@ class SampleActivity : ComponentActivity() {

Button(
onClick = { context.startActivity(Intent(this, T::class.java)) },
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
) {
Text(text = text)
}
Expand Down
76 changes: 76 additions & 0 deletions sample/src/main/java/cafe/adriel/voyager/sample/SampleContent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cafe.adriel.voyager.sample

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ListItem
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import java.util.UUID

val sampleItems: List<String>
get() = (0..99).map { "Item #$it | ${UUID.randomUUID().toString().substringBefore('-')}" }

@Composable
fun LoadingContent() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
CircularProgressIndicator()
}
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ListContent(items: List<String>, onClick: ((Int) -> Unit)? = null) {
LazyColumn {
itemsIndexed(items) { index, item ->
ListItem(
text = { Text(text = item) },
modifier = if (onClick == null) Modifier else Modifier.clickable { onClick(index) }
)
}
}
}

@Composable
fun DetailsContent(instance: Any, item: String, onClick: () -> Unit) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(
text = item,
style = MaterialTheme.typography.h5
)

Spacer(modifier = Modifier.height(16.dp))

Text(
text = instance.toString().substringAfterLast('.'),
style = MaterialTheme.typography.body2
)

Spacer(modifier = Modifier.height(16.dp))

Button(
onClick = onClick,
content = { Text(text = "Back") }
)
}
}

This file was deleted.

Loading

0 comments on commit ecd604a

Please sign in to comment.