Git Product home page Git Product logo

kaustubhpatange / navigator Goto Github PK

View Code? Open in Web Editor NEW
98.0 4.0 5.0 1.67 MB

A small navigation library for Android to ease the use of fragment transactions & handling backstack (also available for Jetpack Compose).

License: Apache License 2.0

Kotlin 99.94% Shell 0.06%
android navigation fragments backstack state-persistence process-death fragment-transitions animations single-activity-pattern tablayout-navigation

navigator's Introduction

navigator

build

Looking for Jetpack Compose implementation of navigator, see here.

A small (Kotlin first) type-safe navigation library for Android to ease the use of fragment transactions with a navigator.navigateTo call (rest is handled for you) & navigating back is as simple as navigator.goBack().

You also get a separate onBackPressed() callback on the child fragments which will be called when this is the current visible fragment & is the one which is going to be removed upon back press.

The library provides some custom transitions like CircularTransform (on top of existing animations), see its use in the sample app here.

If you have any implementation details to cover let me know.

What additional benefits I can get when using this library?

  • Proper handling of Fragment Transaction.
  • Handling up & back press actions efficiently on Fragment.
  • Easy to use API for animations & transitions (see here).
  • Generic Typed Arguments when passing data between destinations (see here).
  • Quick Bottom & Tab navigation setup (see tutorials).

API Reference docs, check here.

Implementation

Maven Central

// root's build.gradle
allprojects {
    repositories {
        mavenCentral()
    }
}
// modules's build.gradle
dependencies {
    implementation "io.github.kaustubhpatange:navigator:<version>" // Core library (Required)
    implementation "io.github.kaustubhpatange:navigator-extensions:<version>" // Optional but recommended
    implementation "io.github.kaustubhpatange:navigator-bottom-navigation:<version>" // For setting up Bottom Navigation.
    implementation "io.github.kaustubhpatange:navigator-tab-navigation:<version>" // For setting up Tab Layout Navigation.
    implementation "io.github.kaustubhpatange:navigator-rail-navigation:<version>" // For setting up Rail Navigation.
}
  • Snapshots

Snapshots of the current development version of navigator are available, which track the latest commit. See here for more information.

Samples

  • Basic sample - Hands on with the introduction to some library features.
  • Backpress sample - A sample focused on handling back press events effectively.
  • Navigation sample - A sample which demonstrate the use of Bottom & Tab navigation supporting multiple backstack through navigator.
  • Multi-Module Navigation sample - Multi-module navigation through navigator using Dagger-Hilt.

Tutorials

Apps using navigator

If you would like me to add your app in the list, let me know through issues.

Name
Moviesy - Client app for YTS movies
XClipper - Clipboard manager for Android & Windows

License

Copyright 2020 Kaustubh Patange

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

https://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.

navigator's People

Contributors

kaustubhpatange avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

navigator's Issues

Bottom sheet in compose navigator?

Love your current implementation and was wondering if you had any plans to add support for modal bottom sheets in the compose library?

Access Argument in ViewModel for Navigator Compose

Is it possible to get Navigation arguments from SavedStateHandle in ViewModels like we can do in Navigation Compose library

private val lectionName: String = savedStateHandle.get("lectionName")!!
private val packName: String = savedStateHandle.get("packName")!!

[Navigator Compose] Design of `singleTop` is different from traditional navigation system

For a very long time, we knew how a single top instance worked in the Fragment's navigation world. Since transactions in the FragmentManager are reversible the only way to correctly achieve this functionality of singleTop is to pop the backstack up to the point where we find that respective instance in the FragmentTransaction. This is how navigator & Jetpack Navigation handles single top functionality.

In Compose world, this could take a different turn since destinations are nothing but a State which we observe to switch between different composables we can remove it at any point without affecting the previous transaction (i.e history). The current implementation does not work like how it was done in Fragments world, here we just remove all the existing instances from the backstack directly (i.e no recursive pop till we find that instance).

This could be confusing since the functionality is not carried over to the new system. Now should I keep or change the logic that we are familiar with Fragments? Changing it would then become a breaking change.

Crash on Production app with IllegalStateException

@KaustubhPatange
I am getting this crash on Live App, could you please take a look at this issue Thanks.

Exception java.lang.IllegalStateException: Restarter must be created only during owner's initialization stage
at androidx.savedstate.SavedStateRegistryController.performAttach (SavedStateRegistryController.kt:45)
at androidx.savedstate.SavedStateRegistryController.performRestore (SavedStateRegistryController.kt:63)
at com.lengo.uni.navigation.navigator_compose.LifecycleController.performRestore$app_allLangRelease (LifecycleController.java:206)
at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$Setup$1$1$1.invoke (ComposeNavigator.kt:1316)
at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$Setup$1$1$1.invoke (ComposeNavigator.kt:1310)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34)
at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$CommonEffect$1$1$1.invoke (ComposeNavigator.kt:1401)
at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$CommonEffect$1$1$1.invoke (ComposeNavigator.kt:1390)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34)
at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke (BoxWithConstraints.kt:69)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke (SubcomposeLayout.kt:770)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke (SubcomposeLayout.kt:448)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable (ActualJvm_jvmKt.java:74)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke (Composer.kt:3193)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke (Composer.kt:3183)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations (SnapshotStateKt__DerivedStateKt.java:252)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations (SnapshotStateKt.java:1)
at androidx.compose.runtime.ComposerImpl.doCompose (Composer.kt:3183)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release (ComposerImpl.java:3119)
at androidx.compose.runtime.CompositionImpl.composeContent (Composition.kt:584)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release (Recomposer.kt:811)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release (Composer.kt:3712)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release (Composer.kt:3712)
at androidx.compose.runtime.CompositionImpl.setContent (Composition.kt:519)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto (SubcomposeLayout.kt:468)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (SubcomposeLayout.kt:441)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (SubcomposeLayout.kt:432)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (LayoutNodeSubcompositionsState.java:421)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose (SubcomposeLayout.kt:732)
at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke-0kLqBqw (BoxWithConstraints.kt:69)
at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke (BoxWithConstraints.kt:67)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s (SubcomposeLayout.kt:590)
at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0 (InnerPlaceable.kt:44)
at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1428)
at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1427)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.kt:2116)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads (SnapshotStateObserver.kt:110)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release (OwnerSnapshotObserver.kt:78)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release (OwnerSnapshotObserver.java:66)
at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release (LayoutNode.java:1427)
at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0 (OuterMeasurablePlaceable.kt:94)
at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0 (OuterMeasurablePlaceable.kt:75)
at androidx.compose.ui.node.LayoutNode.measure-BRTryo0 (LayoutNode.kt:1366)
at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s (Box.kt:137)
at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0 (InnerPlaceable.kt:44)
at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1428)
at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1427)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.kt:2116)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads (SnapshotStateObserver.kt:110)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release (OwnerSnapshotObserver.kt:78)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release (OwnerSnapshotObserver.java:66)
at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release (LayoutNode.java:1427)
at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0 (OuterMeasurablePlaceable.kt:94)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release (LayoutNode.java:1381)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default (LayoutNode.java:1372)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA (MeasureAndLayoutDelegate.kt:187)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded (MeasureAndLayoutDelegate.kt:274)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded (MeasureAndLayoutDelegate.kt:38)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout (MeasureAndLayoutDelegate.kt:208)
at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout (AndroidComposeView.android.kt:757)
at androidx.compose.ui.node.Owner.measureAndLayout$default (Owner.java:196)
at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw (AndroidComposeView.android.kt:954)
at android.view.View.draw (View.java:23190)

Write Tests

This is to remind me that I must write tests when the API is stable or there will be no breaking change.

I was thinking to write tests for the sample application & check if their behaviors are expected because testing each edge case with the navigator might take a lot of time. This maybe a good idea but will see!

Navigation Compose scoped view models

Hi again :)

So I'm trying to have scoped viewModels to screens with hilt and this is quite an headache due to the current hilt limitations.

Do you have any plans to add support for something equivalent to hiltViewModel from compose navigation?

There is a problem with the example module

Hello, I used this library as a practice code. When I first saw it, I thought this library was very useful. Then I used the leakcanary memory leak detection tool to check some code of the example, here are some problems:

multi-modlue-sample:

Snipaste_2022-05-11_16-22-40
Snipaste_2022-05-11_16-25-51

navigation-sample

Snipaste_2022-05-11_16-40-12
Snipaste_2022-05-11_16-42-12

Posted where the memory leaked and the modified code.The test is not complete, there may be undetected, only these two example modules are tested

Crashes if call goBack() after navigateTo()

Case:
Fragment1 navigateTo() Fragment2
Fragment2 check condition, if data is invalid -> backTo() Fragment1 => crashes

It works if I use Handle.postDelay()

Fragment 1 Code: onViewCreated()

     getView()?.findViewById<TextView>(R.id.text)?.setOnClickListener {
        getView()?.findViewById<TextView>(R.id.text)?.text = "Clicked"
        val options = FragmentNavigator.NavOptions(
            transaction = FragmentNavigator.TransactionType.REPLACE,
            animation = AnimationDefinition.Zoom
        )
        (activity as MainActivity).navigate.navigateTo(Fragment2(),options)
    }

Fragment 2 code: onViewCreated()

     getView()?.findViewById<TextView>(R.id.text)?.setOnClickListener {
        getView()?.findViewById<TextView>(R.id.text)?.text = "Clicked"
        val options = FragmentNavigator.NavOptions(
            transaction = FragmentNavigator.TransactionType.ADD,
            animation = AnimationDefinition.Zoom
        )
        (activity as MainActivity).navigate.navigateTo(Fragment3(),options)
    }

    //Handler().postDelayed({
        (activity as MainActivity).navigate.goBack()
    //}, 1)

[Question] - How to use fragment manager?

if (this::navigate.isInitialized) { childFragmentManager.addOnBackStackChangedListener { Timber.e("addOnBackStackChangedListener") val fragment = navigate.getCurrentFragment() ?: return@addOnBackStackChangedListener if (fragment is BaseFragment<*>) { fragment.onFragmentResume() } } }

Im using navigator(inside fragment) to manage my fragments but when I use above code to addOnBackStackChangedListener nothing happen.
I also tried navigate.getFragmentManager() but does not work

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.