Skip to content

Commit

Permalink
Merge branch 'refs/heads/predictive-back' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
matejdro committed Sep 13, 2024
2 parents fa4a35d + d5614b1 commit 7a46a78
Show file tree
Hide file tree
Showing 31 changed files with 349 additions and 152 deletions.
3 changes: 3 additions & 0 deletions .idea/.gitignore

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

1 change: 1 addition & 0 deletions config/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ potential-bugs:
active: false
MissingPackageDeclaration:
active: true
excludes: [ '**/*.kts' ]
NullableToStringCall:
active: true
UnconditionalJumpStatementInLoop:
Expand Down
2 changes: 1 addition & 1 deletion config/hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

./gradlew --continue --parallel -Pprecommit=true buildSrc:detekt detektMetadataMain detektJvmMain detektAndroidDebug detektAndroidRelease detektJvmTest detektMain detektTest :kotlinova-gradle:detektMain reportMerge
./gradlew -q --continue --parallel -Pprecommit=true buildSrc:detekt detekt
2 changes: 1 addition & 1 deletion config/libs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ androidx-activity = "1.9.1"
# See https://developer.android.com/jetpack/androidx/releases/compose-kotlin
androidx-compose-compiler = "1.5.14"
androidx-compose-material3 = "1.2.1"
androidx-compose-runtime = "1.6.8"
androidx-compose-runtime = "1.7.1"
androidx-core = "1.13.1"
androidx-fragment = "1.8.2"
androidx-lifecycle = "2.8.4"
Expand Down
33 changes: 33 additions & 0 deletions navigation/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,39 @@ class LoginConditionalNavigationHandler @Inject constructor(
See [login example](sample/conditional/src/main/java/si/inova/kotlinova/navigation/sample/conditional)
for more information.

## Predictive back gesture

Library supports predictive back out of the box. When is performing the back gesture, he/she is controlling the
progress of the backward animation (see "Custom animations" above).

To enable, you just opt-in in your Android Manifest:

```xml

<application...android:enableOnBackInvokedCallback="true"... >...</application>
```

See [Android documentation](https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture#opt-predictive) for
more info.

You can customize the back animation based on which side user swipes from by accessing `scope.targetState.backSwipeEdge` property
in the animation declaration:

```kotlin
abstract class MyScreenKey : ScreenKey() {
override fun backAnimation(scope: AnimatedContentTransitionScope<StateChangeResult>): ContentTransform {
val animation = when (scope.targetState.backSwipeEdge) {
BackEventCompat.EDGE_LEFT ->...
BackEventCompat.EDGE_RIGHT
->...
else ->... // Not predictive back
}

...
}
}
```

## Navigating to fragments

Navigation also has an optional `navigation-fragment` library that allows navigation to fragments instead of to 100% compose
Expand Down
2 changes: 1 addition & 1 deletion navigation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ android {
dependencies {
api(libs.simpleStack)
api(libs.dagger.runtime) // This needs to be API to ensure generated files compile
api(libs.androidx.activity.compose)

implementation(projects.kotlinova.core)

implementation(libs.androidx.core)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.animation)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
Expand Down
2 changes: 2 additions & 0 deletions navigation/sample/.idea/.gitignore

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

1 change: 1 addition & 0 deletions navigation/sample/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ android {

anvil {
syncGeneratedSources.set(true)
addOptionalAnnotations = true
}
}

Expand Down
6 changes: 4 additions & 2 deletions navigation/sample/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 INOVA IT d.o.o.
~ Copyright 2024 INOVA IT d.o.o.
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
~ files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand Down Expand Up @@ -28,7 +28,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.NavigationDemoTheme"
android:name=".NavigationSampleApplication"
tools:targetApi="31">
android:enableOnBackInvokedCallback="true"
tools:targetApi="31"
tools:ignore="UnusedAttribute">
<activity
android:name="si.inova.kotlinova.navigation.sample.MainActivity"
android:exported="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package si.inova.kotlinova.navigation.sample

import android.app.Application
import com.deliveryhero.whetstone.SingleIn
import com.deliveryhero.whetstone.app.ApplicationComponent
import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.MergeComponent
Expand All @@ -27,7 +26,6 @@ import si.inova.kotlinova.navigation.di.OuterNavigationScope
import javax.inject.Singleton

@Singleton
@SingleIn(ApplicationScope::class)
@MergeComponent(ApplicationScope::class)
@MergeComponent(OuterNavigationScope::class)
interface NavigationSampleApplicationComponent : ApplicationComponent {
Expand Down
22 changes: 22 additions & 0 deletions navigation/sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
// https://youtrack.jetbrains.com/issue/KTIJ-19369
@file:Suppress("DSL_SCOPE_VIOLATION")

import com.android.build.gradle.BaseExtension

buildscript {
repositories {
google()
Expand All @@ -30,3 +32,23 @@ buildscript {
classpath(libs.kotlin.plugin)
}
}

subprojects {
afterEvaluate {
extensions.configure<BaseExtension>("android") {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}

dependencies {
add("coreLibraryDesugaring", libs.desugarJdkLibs)
}
}

configurations.all {
resolutionStrategy {
force("com.squareup.anvil:annotations-optional:2.5.0-beta09")
}
}
}
32 changes: 17 additions & 15 deletions navigation/sample/config/libs.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
[versions]
androidGradlePlugin = "7.4.2"
androidx-activity-compose = "1.8.0"
androidx-core = "1.12.0"
androidx-compose-compiler = "1.5.3"
androidx-compose-runtime = "1.5.4"
androidx-compose-material3 = "1.1.2"
androidx-fragment = "1.6.2"
androidx-lifecycle = "2.6.2"
anvil = "2.4.8"
dagger = "2.48.1"
kotlin = "1.9.10"
kotlinova = "3.0.0-alpha20"
whetstone = "0.5.1"
androidGradlePlugin = "8.4.2"
androidx-activity-compose = "1.9.0"
androidx-core = "1.13.1"
androidx-compose-compiler = "1.5.14"
androidx-compose-runtime = "1.7.0-beta02"
androidx-compose-material3 = "1.2.1"
androidx-fragment = "1.8.0"
androidx-lifecycle = "2.7.0"
anvil = "2.5.0-beta09"
dagger = "2.51.1"
desugarJdkLibs = "2.0.4"
kotlin = "1.9.24"
kotlinova = "3.1.0"
whetstone = "0.9.0-beta02"

[libraries]
android-agp = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" }
Expand All @@ -29,10 +30,11 @@ androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", versi
androidx-compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "androidx-compose-material3" }
dagger-runtime = { module = "com.google.dagger:dagger", version.ref = "dagger" }
dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugarJdkLibs" }
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlinova-navigation = { module = "si.inova.kotlinova:navigation", version.ref = "kotlinova" }
kotlinova-navigation-fragment = { module = "si.inova.kotlinova:navigation-fragment", version.ref = "kotlinova" }
kotlinova-navigation-compiler = { module = "si.inova.kotlinova:navigation-compiler", version.ref = "kotlinova" }
anvil = { module = "com.squareup.anvil:gradle-plugin", version.ref = "anvil" }
whetstone-compiler = { module = "com.deliveryhero.whetstone:whetstone-compiler", version.ref = "whetstone" }
whetstone-runtime = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "whetstone" }
whetstone-compiler = { module = "dev.msfjarvis.whetstone:whetstone-compiler", version.ref = "whetstone" }
whetstone-runtime = { module = "dev.msfjarvis.whetstone:whetstone", version.ref = "whetstone" }
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package si.inova.kotlinova.navigation.sample.fragment

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
Expand All @@ -34,6 +35,7 @@ class DemoFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return TextView(requireContext()).apply {
text = "Hello From Fragment. Got argument: ${arguments?.getInt(ARGUMENT_INPUT)}"
setTextColor(Color.WHITE)
}
}

Expand Down
4 changes: 2 additions & 2 deletions navigation/sample/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip
distributionSha256Sum=312eb12875e1747e05c2f81a4789902d7e4ec5defbd1eefeaccc08acf096505d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
distributionSha256Sum=f8b4f4772d302c8ff580bc40d0f56e715de69b163546944f787c87abf209c961
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -18,11 +18,11 @@ package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.fragment.FragmentScreenKey
import si.inova.kotlinova.navigation.screenkeys.ScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey
import java.util.UUID

@Parcelize
data class DemoFragmentScreenKey(
val inputNumber: Int,
override val tag: String = UUID.randomUUID().toString()
) : ScreenKey(), FragmentScreenKey
) : BaseScreenKey(), FragmentScreenKey
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -17,7 +17,7 @@
package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.NoArgsScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey

@Parcelize
object MainScreenKey : NoArgsScreenKey()
data object MainScreenKey : BaseScreenKey()
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -17,7 +17,7 @@
package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.NoArgsScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey

@Parcelize
object NestedScreenKey : NoArgsScreenKey()
data object NestedScreenKey : BaseScreenKey()
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -17,7 +17,7 @@
package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.NoArgsScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey

@Parcelize
object RootConditionalNavigationScreenKey : NoArgsScreenKey()
data object RootConditionalNavigationScreenKey : BaseScreenKey()
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -17,13 +17,13 @@
package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.ScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey
import java.util.UUID

// Adding same keys to the backstack is not allowed.
// That's why we add a random id to the screen's key to make it unique and allow stacking.
@Parcelize
data class SharedViewModelScreenKey(private val id: UUID = UUID.randomUUID()) : ScreenKey() {
data class SharedViewModelScreenKey(private val id: UUID = UUID.randomUUID()) : BaseScreenKey() {
override fun getScopeTag(): String {
// Any screens whose keys share the same scope name, will share their scoped services
return "SharedScope"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -16,20 +16,18 @@

package si.inova.kotlinova.navigation.sample.keys

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import com.zhuinden.simplestack.StateChange
import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.ScreenKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseScreenKey
import si.inova.kotlinova.navigation.simplestack.StateChangeResult

@Parcelize
data class SlideAnimationScreenKey(val argument: String) : ScreenKey() {
data class SlideAnimationScreenKey(val argument: String) : BaseScreenKey() {
override fun forwardAnimation(scope: AnimatedContentTransitionScope<StateChangeResult>): ContentTransform {
return if (scope.targetState.direction == StateChange.REPLACE) {
fadeIn() togetherWith fadeOut()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 INOVA IT d.o.o.
* Copyright 2024 INOVA IT d.o.o.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
Expand All @@ -17,11 +17,11 @@
package si.inova.kotlinova.navigation.sample.keys

import kotlinx.parcelize.Parcelize
import si.inova.kotlinova.navigation.screenkeys.SingleTopKey
import si.inova.kotlinova.navigation.sample.keys.base.BaseSingleTopScreenKey

// SingleTopKey will cause navigation to not actually navigate, but to only recompose the top screen with the new key.
@Parcelize
data class TabScreenKey(val selectedTab: SelectedTab = SelectedTab.A) : SingleTopKey() {
data class TabScreenKey(val selectedTab: SelectedTab = SelectedTab.A) : BaseSingleTopScreenKey() {
enum class SelectedTab {
A,
B,
Expand Down
Loading

0 comments on commit 7a46a78

Please sign in to comment.