Skip to content

Commit

Permalink
Lifecycle fixes, documentation updates (#6)
Browse files Browse the repository at this point in the history
• Fix android lifecycle
• Adjust additional info for destination scope
• update readme
  • Loading branch information
vkatz authored Feb 27, 2024
1 parent 05520bd commit 5fd8db0
Show file tree
Hide file tree
Showing 29 changed files with 882 additions and 161 deletions.
Binary file added .readme/1-simple-fb.webm
Binary file not shown.
Binary file added .readme/2-bot-bar.webm
Binary file not shown.
Binary file added .readme/3-data-params.webm
Binary file not shown.
Binary file added .readme/4-data-result.webm
Binary file not shown.
Binary file added .readme/5-custom-transition.webm
Binary file not shown.
3 changes: 3 additions & 0 deletions .readme/hint.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
records compress:

ffmpeg -i 1.mov -c:v libvpx-vp9 -crf 40 -vf scale=3840:-2 -deadline best -an 1.webm
Binary file added .readme/promo.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
315 changes: 306 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,316 @@
[![Maven Central](https://img.shields.io/maven-central/v/io.github.composegears/tiamat)](https://central.sonatype.com/artifact/io.github.composegears/tiamat)
<h1 align="center">Tiamat</h1>
<h2 align="center">Compose multiplatform navigation library</h2>

Tiamat
======
<p align="center">
<a target="_blank" href="https://github.com/ComposeGears/Tiamat/stargazers"><img src="https://img.shields.io/github/stars/ComposeGears/Tiamat.svg"></a>
<a href="https://github.com/ComposeGears/Tiamat/network"><img alt="API" src="https://img.shields.io/github/forks/ComposeGears/Tiamat.svg"/></a>
<a target="_blank" href="https://github.com/ComposeGears/Tiamat/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ComposeGears/Tiamat.svg"></a>
<a target="_blank" href="https://central.sonatype.com/artifact/io.github.composegears/tiamat"><img src="https://img.shields.io/maven-central/v/io.github.composegears/tiamat.svg?style=flat-square"></a>
</p>

`Tiamat` is a kmm navigation library
![](.readme/promo.jpeg)

Add the dependency below to your **module**'s `build.gradle.kts` file:

#### Android / jvm
```kotlin
dependencies {
implementation("io.github.composegears:tiamat:$version")
}
```

#### Multiplatform
```kotlin
sourceSets {
commonMain.dependencies {
implementation("io.github.composegears:tiamat:$version")
}
}
```

Why Tiamat?
-----------

- Code generation free
- Pure compose
- Support nested navigation
- Support back-stack alteration (+deep-links)
- Easy to use
- Allow to pass ANY types as data, even lambdas (!under small condition)
- Customizable transitions

Setup
-----

1) Define your screens in one of 3 available ways:

- chaotic good (screen name eq to value name)

```kotlin
val Screen by navDestination<Unit> {
// content
}
```
- chaotic neutral
```kotlin

val Screen = NavDestination<Unit>("ScreenName") {
// content
}
```
- chaotic evil
```kotlin
object Screen : NavDestination<Unit> {
override val name: String = "ScreenName"

@Composable
override fun NavDestinationScope<Unit>.Content() {
// content
}

}
```
2) Create navController
```kotlin
val navController = rememberNavController(
startDestination = Screen,
destinations = arrayOf(
Screen,
AnotherScreen,
// ...
)
)
```
3) Setup navigation
```kotlin
Navigation(navController)
```
4) Navigate
```kotlin
val Screen by navDestination<Unit> {
val navController = navController()
Column {
Text("Screen")
Button(onClick = { navController.navigate(AnotherScreen) }){
Text("Navigate")
}
}
}
```

see example: [App.kt](example/composeApp/src/commonMain/kotlin/App.kt#L16)

Overview
--------
### Screen

The screens in `Tiamat` should be an entities (similar to composable functions)

the `Args` generic define the type of data, acceptable by screen as `input parameters` in the `NavController:navigate` fun

```kotlin
implementation("io.github.composegears:tiamat:0.1.0-alpha")
val RootScreen by navDestination<Unit> {
// ...
val nc = navController()
// ...
nc.navigate(DataScreen, DataScreenArgs(1))
// ...
}

data class DataScreenArgs(val t: Int)

val DataScreen by navDestination<DataScreenArgs> {
val args = navArgs()
}

```
----
The screen content scoped in `NavDestinationScope<Args>`

The scope provides a number of composable functions:

- `navController` - provides current NavController to navigate back/further
- `navArgs` - the arguments provided to this screen by `NavControllr:navigate(screen, args)` fun
- `navArgsOrNull` - same as `navArgs` but provides `null` if there is no data passed or if it was lost
- `navResult` - provide the data passed to `NavControllr:back(screen, navResult)` as result
- `rememberViewModel` - create or provide view model scoped(linked) to current screen

### NavController

You may create NavController using `rememberNavController` function:

```kotlin
fun rememberNavController(
key: Any? = null,
storageMode: StorageMode? = null,
startDestination: NavDestination<*>? = null,
destinations: Array<NavDestination<*>>
)
```

and display as part of any composable function
```kotlin
@Composable
fun Content() {
val navController = rememberNavController(...)
Navigation(
navController = navController,
modifier = Modifier.fillMaxSize().systemBarsPadding()
)
}
```

NavController will keep the screens data, view models, and states during navigation

> [!IMPORTANT]
> The data may be cleared by system (eg: Android may clear memory)
>
> Upon restoration state there is few cases depend on `storageMode`
### Storage mode

- `null` - will take parent NavController mode or `ResetOnDataLoss` for root controller
- `StorageMode.Savable` - will store data in `savable` storage (eg: Android -> Bundle)
> [!IMPORTANT]
> Only 'Savable' types of params & args will be available to use
>
> eg: Android - Parcelable + any bundlable primitives
- `StorageMode.ResetOnDataLoss` - store data in memory, allow to use any types of args & params (including lambdas). Reset nav controller upon data loss
- `StorageMode.IgnoreDataLoss` - store data in memory, allow to use any types of args & params (including lambdas). Restore nav back stack, ignore data loss

### Known limitations

> [!IMPORTANT]
> `Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly` ide error.
>
>
> ```kotlin
> val SomeScreen1 by navDestination<Unit> {
> val navController = navController()
> Button(
> onClick = { navController.navigate(SomeScreen2) }, // << error here
> content = { Text("goScreen2") }
> )
> }
>
> val SomeScreen2 by navDestination<Unit> {
> val navController = navController()
> Button(
> onClick = { navController.navigate(SomeScreen1) }, // << or here
> content = { Text("goScreen2") }
> )
> }
> ```
>
> Appears when it is circular initialization happen (Screen1 knows about Screen2 whot knows about Screen1 ...)
>
> Solution: just define types of root(any in chain) screens explicitly
>
> ```kotlin
> val SomeScreen1: NavDestination<Unit> by navDestination { // ... }
> ```
> [!IMPORTANT]
> No data exception
>
> Using `storageMode = StorageMode.DataStore.IgnoreDataLoss` in the `rememberNavController`
>
> Within screens `val navArgs = navArgs()`
>
> May cause error in case internal data storage where cleared (eg: Android may release memory of activity)
>
> Solution: there is safe version `val navArgs = navArgsOrNull()`
Samples
-------
#### Simple back and forward navigation:
[1-simple-fb.webm](https://github.com/ComposeGears/Tiamat/assets/3141818/fbf88bc1-d366-4088-ad34-5ac9471d0b18)
#### Bottom bar navigation:
[2-bot-bar.webm](https://github.com/ComposeGears/Tiamat/assets/3141818/e541d4a4-119a-41d4-a1e5-26ef35dc7073)
#### Passing data to next screen:
[3-data-params.webm](https://github.com/ComposeGears/Tiamat/assets/3141818/9d151430-7fe9-47f6-83d2-9c58b700fe9a)
#### Passing data to previous screen:
[4-data-result.webm](https://github.com/ComposeGears/Tiamat/assets/3141818/9706867d-2c88-4d50-8c3d-d5d7d44aade3)
Custom transition:
[5-custom-transition.webm](https://github.com/ComposeGears/Tiamat/assets/3141818/9bfe1545-a321-495f-8d64-8d928746bc81)
### Examples code
- [SimpleForwardBack.kt](example/composeApp/src/commonMain/kotlin/content/examples/SimpleForwardBack.kt) - Simple back and forward navigation
- [SimpleReplace.kt](example/composeApp/src/commonMain/kotlin/content/examples/SimpleReplace.kt) - Example of `replace` navigation
- [NestedNavigation.kt](example/composeApp/src/commonMain/kotlin/content/examples/NestedNavigation.kt) - Nested nav controller interaction
- [Tabs.kt](example/composeApp/src/commonMain/kotlin/content/examples/Tabs.kt) - Bottom navigation example
- [DataPassingParams.kt](example/composeApp/src/commonMain/kotlin/content/examples/DataPassingParams.kt) - How to pass data to next screen
- [DataPassingResult.kt](example/composeApp/src/commonMain/kotlin/content/examples/DataPassingResult.kt) - How to provide result
- [CustomTransition.kt](example/composeApp/src/commonMain/kotlin/content/examples/CustomTransition.kt) - Custom animations/transition
- [BackStackAlteration.kt](example/composeApp/src/commonMain/kotlin/content/examples/BackStackAlteration.kt) - Alteration(modification) of backstack (deeplinks)
- [ViewModels.kt](example/composeApp/src/commonMain/kotlin/content/examples/ViewModels.kt) - ViewModels usage
Hint
----
### Desktop
There is no default 'back' action on desktop
If you want to add one into the `Tiamat` navigation just use the code below:
```kotlin
fun main() = application {
val backHandler = LocalNavBackHandler.current // < get ref to Global back handler
Window(
// ...
onKeyEvent = { // < add global key event handler
it.key == Key.Escape && it.type == KeyEventType.KeyUp && backHandler.back() // < call backHandler.back()
},
// ...
) {
App()
}
}
```
### Android
`Tiamat-android` overrides `LocalLifecycleOwner` for each destination and compatible with lifecycle-aware components
See an example of camera usage: [AndroidViewLifecycleExample.kt](example/composeApp/src/androidMain/kotlin/content/examples/platform/AndroidViewLifecycleExample.kt)
### iOS
Nothing specific (yet)
### Run/Build sample
### Run sample
Android: `./gradlew example:composeApp:assembleDebug`
Desktop: `./gradlew example:composeApp:run`
Base usage
----------
iOS: run XCode project or else use [KMM](https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile) plugin iOS target
TODO
# License
```xml
Developed by ComposeGears 2024
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
6 changes: 5 additions & 1 deletion example/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ kotlin {
val desktopMain by getting

androidMain.dependencies {
implementation(libs.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.view)
implementation(libs.androidx.concurrent.futures)
implementation(libs.compose.ui.tooling.preview)
}
commonMain.dependencies {
implementation(projects.tiamat)
Expand Down
3 changes: 3 additions & 0 deletions example/composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>

<application
android:allowBackup="true"
android:label="@string/app_name"
Expand Down
Loading

0 comments on commit 5fd8db0

Please sign in to comment.