Skip to content

Commit

Permalink
Added functionality to allow generic types to be bound with @Navigati…
Browse files Browse the repository at this point in the history
…onDestination for Fragments, Activities and Composables
  • Loading branch information
isaac-udy committed Nov 1, 2022
1 parent 3e207ca commit b12b914
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class NavigationDestinationProcessor : BaseProcessor() {
)
)
""".trimIndent(),
keyType
ClassName.get(keyType)
)
)
.build()
Expand Down Expand Up @@ -240,7 +240,7 @@ class NavigationDestinationProcessor : BaseProcessor() {
)
)
""".trimIndent(),
key,
ClassName.get(key as TypeElement),
destination
)

Expand All @@ -253,7 +253,7 @@ class NavigationDestinationProcessor : BaseProcessor() {
)
)
""".trimIndent(),
key,
ClassName.get(key as TypeElement),
destination
)

Expand All @@ -266,7 +266,15 @@ class NavigationDestinationProcessor : BaseProcessor() {
)
)
""".trimIndent(),
key,
ClassName.get((key as TypeElement).apply {
if (typeParameters.isNotEmpty()) {
processingEnv.messager.printMessage(
Diagnostic.Kind.ERROR,
"${key.getElementName()} has generic type parameters, and is bound to a SyntheticDestination. " +
"Type parameters are not supported for SyntheticDestinations as this time"
)
}
}),
destination
)
else -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package dev.enro.core.compose

import android.os.Parcelable
import dev.enro.core.destinations.*
import junit.framework.TestCase.assertEquals
import kotlinx.parcelize.Parcelize
import org.junit.Test
import java.util.*

class ComposableDestinationPresent {
@Test
Expand All @@ -11,6 +15,20 @@ class ComposableDestinationPresent {
root.assertPresentsTo<ComposableDestination, ComposableDestinations.Presentable>()
}

@Parcelize
data class ParcelableForTest(
val parcelableId: String
) : Parcelable

@Test
fun givenComposableDestination_whenExecutingPresent_andTargetIsGenericComposableDestination_thenCorrectDestinationIsOpened() {
val root = launchComposableRoot()
val expectedKey = ComposableDestinations.Generic(ParcelableForTest(UUID.randomUUID().toString()))

val context = root.assertPresentsTo<ComposableDestination, ComposableDestinations.Generic<ParcelableForTest>>(expectedKey)
assertEquals(expectedKey, context.navigation.key)
}

@Test
fun givenComposableDestination_whenExecutingPresent_andTargetIsComposableDestination_andDestinationIsClosed_thenPreviousDestinationIsActive() {
val root = launchComposableRoot()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.enro.core.destinations

import android.os.Parcelable
import dev.enro.TestActivity
import dev.enro.annotations.NavigationDestination
import dev.enro.core.NavigationKey
Expand All @@ -20,6 +21,13 @@ object ActivityDestinations {
val id: String = UUID.randomUUID().toString()
) : NavigationKey.SupportsPresent.WithResult<TestResult>

// This type is not actually used in any tests at present, but just exists to prove
// that generic navigation destinations will correctly generate code
@Parcelize
data class Generic<Type: Parcelable>(
val item: Type
) : NavigationKey.SupportsPush

abstract class Activity : TestActivity() {
private val navigation by navigationHandle<NavigationKey>()
private val primaryContainer by navigationContainer(primaryFragmentContainer) {
Expand All @@ -38,4 +46,7 @@ object ActivityDestinations {
class ActivityDestinationsRootActivity : ActivityDestinations.Activity()

@NavigationDestination(ActivityDestinations.Presentable::class)
class ActivityDestinationsPresentableActivity : ActivityDestinations.Activity()
class ActivityDestinationsPresentableActivity : ActivityDestinations.Activity()

@NavigationDestination(ActivityDestinations.Generic::class)
class ActivityDestinationsGenericActivity : ActivityDestinations.Activity()
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.enro.core.destinations

import android.os.Parcelable
import androidx.compose.material.Card
import androidx.compose.runtime.Composable
import androidx.compose.ui.window.Dialog
Expand Down Expand Up @@ -62,6 +63,13 @@ object ComposableDestinations {
val id: String = UUID.randomUUID().toString()
) : NavigationKey.SupportsPush, TestDestination.IntoPrimaryContainer

// This type is not actually used in any tests at present, but just exists to prove
// that generic navigation destinations will correctly generate code
@Parcelize
data class Generic<Type: Parcelable>(
val item: Type
) : NavigationKey.SupportsPresent

class TestViewModel : ViewModel() {
private val navigation by navigationHandle<NavigationKey>()
val resultChannel by registerForNavigationResult<TestResult> {
Expand Down Expand Up @@ -165,3 +173,12 @@ fun ManuallyBoundComposableScreen() {
viewModel<ComposableDestinations.TestViewModel>()
TestComposable(name = "ManuallyDefinedComposable")
}

@Composable
@NavigationDestination(ComposableDestinations.Generic::class)
fun GenericComposableScreen() {
viewModel<ComposableDestinations.TestViewModel>()
val navigation = navigationHandle<ComposableDestinations.Generic<*>>()
TestComposable(name = "GenericComposable\n${navigation.key.item}")
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.enro.core.destinations

import android.os.Parcelable
import dev.enro.TestDialogFragment
import dev.enro.TestFragment
import dev.enro.annotations.NavigationDestination
Expand Down Expand Up @@ -46,6 +47,13 @@ object FragmentDestinations {
val id: String = UUID.randomUUID().toString()
) : NavigationKey.SupportsPush.WithResult<TestResult>, TestDestination.IntoSecondaryChildContainer

// This type is not actually used in any tests at present, but just exists to prove
// that generic navigation destinations will correctly generate code
@Parcelize
data class Generic<Type: Parcelable>(
val item: Type
) : NavigationKey.SupportsPresent

abstract class Fragment(
primaryContainerAccepts: (NavigationKey) -> Boolean,
secondaryContainerAccepts: (NavigationKey) -> Boolean,
Expand Down Expand Up @@ -111,4 +119,10 @@ class FragmentDestinationPushesToChildAsPrimary : FragmentDestinations.Fragment(
class FragmentDestinationPushesToChildAsSecondary : FragmentDestinations.Fragment(
primaryContainerAccepts = { false },
secondaryContainerAccepts = { false }
)

@NavigationDestination(FragmentDestinations.Generic::class)
class FragmentDestinationGeneric : FragmentDestinations.Fragment(
primaryContainerAccepts = { false },
secondaryContainerAccepts = { false }
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package dev.enro.core.fragment

import android.os.Parcelable
import androidx.fragment.app.Fragment
import dev.enro.core.compose.ComposableDestination
import dev.enro.core.destinations.*
import junit.framework.TestCase
import kotlinx.parcelize.Parcelize
import org.junit.Test
import java.util.*

class FragmentDestinationPresent {
@Test
Expand All @@ -12,6 +17,20 @@ class FragmentDestinationPresent {
root.assertPresentsTo<ComposableDestination, ComposableDestinations.Presentable>()
}

@Parcelize
data class ParcelableForTest(
val parcelableId: String
) : Parcelable

@Test
fun givenFragmentDestination_whenExecutingPresent_andTargetIsGenericFragmentDestination_thenCorrectDestinationIsOpened() {
val root = launchFragmentRoot()
val expectedKey = FragmentDestinations.Generic(ParcelableForTest(UUID.randomUUID().toString()))

val context = root.assertPresentsTo<Fragment, FragmentDestinations.Generic<ParcelableForTest>>(expectedKey)
TestCase.assertEquals(expectedKey, context.navigation.key)
}

@Test
fun givenFragmentDestination_whenExecutingPresent_andTargetIsComposableDestination_andDestinationIsClosed_thenPreviousDestinationIsActive() {
val root = launchFragmentRoot()
Expand Down

0 comments on commit b12b914

Please sign in to comment.