Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Jetpack navigation module #351

Closed
wants to merge 3 commits into from

Conversation

marukami
Copy link
Contributor

@marukami marukami commented Feb 15, 2020

  • Navigation 2.2.0 requires Java8. So, everything was updated to Java8
  • Add a navGraphViewModel for navigation graph view models
  • navigationLifecycleAwareLazy a slightly forked lifecycleAwareLazy that subscribes the MvRx view when possible and if not defers the lazy until the fragment access the view model
  • MvRxNavDirections a NavDirections that makes it a little easier to pass an argument Parcelable and set the navigation label if provided
  • Added very basic example navigation repo.
  • Added Test Fragment scenario for navigation module.

NOTES

  • The mvrx view needs to wait for until at least the onViewCreated callback. During lifecycle flows like re-configuration the NavHostFragment is not accessible until after the activity onCreate has finished.
  • Oops accidentally deleted branch for Add Jetpack navigation module #337 and it closed the PR 😅

@jpventura
Copy link
Contributor

@elihart @gpeal both #364 and #367 refactors were made to reduce the unnecessary code of inserted by this pull request.

I would like to know if, once it is approved, you have any plans of merging it into MvRx project or if you will keep it as a suggestion. Maybe we could split @marukami code into two PRs (one fore mvrx-navigation and another for hello-navigation).

Please let me know if you have any further questions.

@marukami marukami force-pushed the navigation-viewmodel-store branch 4 times, most recently from d6b3c80 to 02c586f Compare April 2, 2020 23:27
@marukami
Copy link
Contributor Author

marukami commented Apr 2, 2020

@elihart @gpeal both #364 and #367 refactors were made to reduce the unnecessary code of inserted by this pull request.

I would like to know if, once it is approved, you have any plans of merging it into MvRx project or if you will keep it as a suggestion. Maybe we could split @marukami code into two PRs (one fore mvrx-navigation and another for hello-navigation).

Please let me know if you have any further questions.

@jpventura #364 and #367 Look good to me thanks.

I would like to know if, once it is approved, you have any plans of merging it into MvRx project or if you will keep it as a suggestion.

Getting it merged would be good. I update the PR to remove the example as androidx.navigation@2.3.0 adds a test NavHost that makes creating some tests actually possible. Tho, the Navigation component does not seem to work in test src, so, I put the test code in debug… not the best fix, hopefully, that's serviceable as an OK-ish workaround.

Maybe we could split @marukami code into two PRs (one fore mvrx-navigation and another for hello-navigation).

Yep, an example module a separate PR works.

@elihart @gpeal let me know what you think about this revised PR.

@@ -74,6 +73,7 @@ ext {
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}",
kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:${versions.kotlin}",
lifecycleExtensions : "androidx.lifecycle:lifecycle-extensions:${versions.lifecycle}",
lifecycleCommonJava8 : "androidx.lifecycle:lifecycle-common-java8:${versions.lifecycle}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

All versions, libraries, testLibraries, and androidTestLibraries were lexicographically sorted. Also Java 8 should be the default compiler across all modules.

Maybe lifecycleCommon would be more semantic/consistent name. Does it make sense @marukami?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

were lexicographically sorted

Ah, I see. lifecycleCommon seems fine

@@ -20,8 +20,8 @@ android {
}

compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceCompatibility JavaVersion.VERSION_1_8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

toolVersion = "0.8.2"
}

dependencies {
Copy link
Contributor

@jpventura jpventura Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep dependencies lexicographycally sorted 😉

dependencies {
    implementation libraries.kotlin
    implementation libraries.lifecycleCommon
    implementation project(":mvrx")
    implementation project(":testing")
    
    testImplementation libraries.rxAndroid
    testImplementation testLibraries.junit
    testImplementation testLibraries.mockito
    testImplementation testLibraries.roboeletric
}


// module specific dependencies
dependencies {
def nav_version = "2.3.0-alpha04"
Copy link
Contributor

@jpventura jpventura Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami I also had hard times with alpha libraries from Google.

Since this would be part of an official Airbnb library, maybe it would be better using the latest stable navigation-fragment-ktx (in dependencies.gradle file it is currently set to 2.2.1).

@elihart @gpeal any words on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami I also had hard times with alpha libraries from Google.

I've found the Androidx stuff to be fine and most issues you can workaround. Far as I can tell Stable and Alpha are mostly the same except the newer APIs, tho this is Andoidx and Google so who knows how they are composing the stable and alpha channel code.

For the Alpha here I was planning to use the TestNavHostController that comes in the 2.3.0-alpha; I've found it a lot better than mocking in a few projects. Tho, I did not end up using it, so, yer I think 2.2.1 should work.

2.2.1 it is then.

}

// module specific dependencies
dependencies {
Copy link
Contributor

@jpventura jpventura Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using your branch in a personal project of mine (that is the whole reason why I was pushing the refactors 😉).

@marukami I was trying to figure out why you made two separated segments of dependencies into this build.gradle.

Does not api already suggests that a package is restricted to the module?

Copy link
Contributor

@jpventura jpventura Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some libraries already are saved at dependencies.gradle:

dependencies {
    api libraries.navigationFragmentKtx
    api libraries.navigationUiKtx
    api libraries.rxAndroid

    debugApi libraries.fragment
    debugApi libraries.fragmentKtx

    implementation libraries.kotlin
    implementation libraries.lifecycleCommon
    implementation project(":mvrx")
    implementation project(":testing")

    debugImplementation libraries.fragmentTesting

    testImplementation testLibraries.junit
    testImplementation testLibraries.mockito
    testImplementation testLibraries.navigationTesting
    testImplementation testLibraries.roboeletric
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to figure out why you made two separate segments of dependencies into this build.gradle.

We do not need dependencies.gradle here as these libraries are not shared with any other module and having a separator like a 2nd dependencies seemed like a nice way to segment the core project dependencies from the module-specific dependencies.

Does not api already suggests that a package is restricted to the module?

That rule seems a bit oversimplified. It's an OK rule of thumb inside a project module as for a Library I'm not sure. Tho in a library I don't think it's a restricted module otherwise then we would API include most things.

The assumption is here is the same as with implementation for Koltin STD and AppCompat. In that the consumer is assumed to already be including the navigation-component modules otherwise they can't have a navigation graph to attach the ViewModel.

Tho, I've not managed many libraries and I migth be missing something here.


api libraries.rxAndroid
api libraries.rxJava
api libraries.lifecycleCommonJava8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api libraries.lifecycleCommon
api libraries.rxAndroid
api libraries.rxJava

@@ -101,11 +101,13 @@ data class FragmentViewModelContext(
/**
* The fragment owner of the ViewModel.
*/
val fragment: Fragment
val fragment: Fragment,
private val ownerProvider: ViewModelStoreOwner = fragment,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami name suggestion: storeOwner

@@ -16,7 +14,7 @@ private object UninitializedValue
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@SuppressWarnings("Detekt.ClassNaming")
class lifecycleAwareLazy<out T>(private val owner: LifecycleOwner, initializer: () -> T) : Lazy<T>, Serializable {
class lifecycleAwareLazy<out T>(owner: LifecycleOwner, initializer: () -> T) : Lazy<T>, Serializable, DefaultLifecycleObserver {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami suggestion

class lifecycleAwareLazy<out F>(
    owner: LifecycleOwner,
    initializer: () -> F
) : Lazy<F>, Serializable, DefaultLifecycleObserver {

I don't know what is the correct Kotlin style according Google/JetBrains when there are tons of parameters and interfaces, but this is the way I cheat the linter and keep things readable (well, at least it does not complain 😉)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what is the correct Kotlin style according Google/JetBrains

There isn't one 😀 I find it a bit hard as the project style XML seems to be at odds with the detetkt rules and AS keeps differing from the projects actual rules.

I only removed the private scope access. I guess we can update the style to match things while we are here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what is the correct Kotlin style according Google/JetBrains when there are tons of parameters and interfaces, but this is the way I cheat the linter and keep things readable (well, at least it does not complain 😉)

This project has code style checked into git, so you can set this up to be done automatically via code reformatting (ctrl+alt+L or command+option+L by default in Android Studio). The code style for this is kotlin -> wrapping and braces -> function declaration parameters -> chop down if long.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I made this PR this was the project style. After #387 is merged I'm going to rebase and format to match the updated styles.

enabled = false
}

task coverage(type: JacocoReport, dependsOn: "testDebugUnitTest") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami absolute n00b Gradle question:

Since this task is also present at mvrx, could it be moved to the root build.gradle file?

Copy link
Contributor Author

@marukami marukami Apr 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the best way is to create a named task in buildSrc and then loop over subprojects and register the task to every module. The tricky thing here is that we have example modules mixed in. Given we only have a few modules a simple custom plugin would reduce the most code per module.

@jpventura
Copy link
Contributor

@marukami I don't know what are @elihart and @gpeal roadmap about replacing Rx by Kotlin coroutines).

If your features will be merged after #347, build navigation module over coroutines branch could speed up integrating your features in the next release.

@jpventura
Copy link
Contributor

@marukami my last pull request broke Travis CI environment just because my code was not following the correct style, just like yours 😄

Adding this to .git/hooks/pre-push protected my from my future me:

#!/usr/bin/env bash

./gradlew lintFix && ./gradlew test

@marukami
Copy link
Contributor Author

marukami commented Apr 5, 2020

@marukami my last pull request broke Travis CI environment just because my code was not following the correct style, just like yours 😄

Adding this to .git/hooks/pre-push protected my from my future me:

#!/usr/bin/env bash

./gradlew lintFix && ./gradlew test

Righto. Are CI jobs only master, not PRs?

OK then that's easy to fix

Copy link
Contributor

@elihart elihart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marukami Thanks for all your work on this. Sorry it's taken us a while to get to, I'll try to spend some time on this soon

@gpeal
Copy link
Collaborator

gpeal commented Aug 14, 2020

@marukami I'd like to merge this before your other PR so you can include a sample. Without it, it won't be easy for people to figure out how to use it.

However, I think you may have mis-targeted this PR. It is targeting master. Did you intend to target release/2.0.0?

@marukami
Copy link
Contributor Author

However, I think you may have mis-targeted this PR. It is targeting master. Did you intend to target release/2.0.0?

Ah, yes, I was working on a release/2.0.0 variant. Will fix up today.

@marukami marukami force-pushed the navigation-viewmodel-store branch 3 times, most recently from 1ea1191 to eb3d684 Compare August 17, 2020 03:03
# Conflicts:
#	CHANGELOG.md
#	mvrx/src/main/kotlin/com/airbnb/mvrx/MvRxViewModelFactory.kt
* added navigationLifecycleAwareLazy as Navigation ViewModel need to wait for onStart to safely access the navController
@marukami
Copy link
Contributor Author

marukami commented Sep 6, 2020

@marukami I'd like to merge this before your other PR so you can include a sample. Without it, it won't be easy for people to figure out how to use it.

However, I think you may have mis-targeted this PR. It is targeting master. Did you intend to target release/2.0.0?

@gpeal I fix up my git for this 1.0 PR and push up #443 for the 2.0 release.

@gpeal
Copy link
Collaborator

gpeal commented Jan 2, 2021

Closed by #443

@gpeal gpeal closed this Jan 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants