blob: e3de833d66cb7462a59a1a0d773f3566643390ca [file] [log] [blame] [edit]
/*
* Copyright 2024 The Android Open Source Project
*
* 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.
*/
package androidx.navigation.fragment.compose
import android.content.Context
import android.util.AttributeSet
import androidx.compose.runtime.Composable
import androidx.navigation.NavArgument
import androidx.navigation.NavDestination
import androidx.navigation.NavType
import androidx.navigation.Navigator
import androidx.navigation.NavigatorProvider
import androidx.navigation.fragment.FragmentNavigator
import androidx.navigation.get
/**
* This Navigator intercepts the inflation of `navigation` destinations in a Navigation with
* Fragment XML file, reusing the `android:name` field as the fully qualified name of the composable
* function to use as the contents of the inflated destination.
*
* Internally, this uses a [ComposableFragment] to implement the reflection call.
*/
@Navigator.Name("composable")
class ComposableFragmentNavigator(private val fragmentNavigator: FragmentNavigator) :
Navigator<FragmentNavigator.Destination>() {
/**
* Construct a [ComposableFragmentNavigator] by retrieving the associated [FragmentNavigator]
* from [provider].
*/
constructor(provider: NavigatorProvider) : this(provider[FragmentNavigator::class])
override fun createDestination(): FragmentNavigator.Destination {
// Note how we associate the destination with the given
// fragmentNavigator - not this Navigator. This ensures
// that the default FragmentNavigator controls the actual
// navigate / popBackStack calls, not us.
return Destination(fragmentNavigator)
}
@NavDestination.ClassType(Composable::class)
internal class Destination(fragmentNavigator: Navigator<out FragmentNavigator.Destination>) :
FragmentNavigator.Destination(fragmentNavigator) {
override fun onInflate(context: Context, attrs: AttributeSet) {
super.onInflate(context, attrs)
// The className that was parsed out is actually the fully
// qualified name of the Composable Function to run, so extract
// that and add it as a default argument on the destination
val fullyQualifiedName = className
val navArgument =
NavArgument.Builder()
.setType(NavType.StringType)
.setDefaultValue(fullyQualifiedName)
.build()
addArgument(ComposableFragment.FULLY_QUALIFIED_NAME, navArgument)
// And then ensure that the actual Fragment that is constructed
// is our ComposableFragment
setClassName(ComposableFragment::class.java.name)
}
}
}