[go: nahoru, domu]

blob: 951bbf8e9cfcb86ba98f5330be8e96aa449a0932 [file] [log] [blame]
/*
* Copyright 2018 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
import androidx.annotation.IdRes
import androidx.core.os.bundleOf
@DslMarker
public annotation class NavDestinationDsl
/**
* DSL for constructing a new [NavDestination]
*/
@NavDestinationDsl
public open class NavDestinationBuilder<out D : NavDestination> internal constructor(
/**
* The navigator the destination was created from
*/
protected val navigator: Navigator<out D>,
/**
* The destination's unique ID.
*/
@IdRes public val id: Int,
/**
* The destination's unique route.
*/
public val route: String?
) {
/**
* DSL for constructing a new [NavDestination] with a unique id.
*
* This sets the destination's [route] to `null`.
*
* @param navigator navigator used to create the destination
* @param id the destination's unique id
*
* @return the newly constructed [NavDestination]
*/
@Deprecated(
"Use routes to build your NavDestination instead",
ReplaceWith("NavDestinationBuilder(navigator, route = id.toString())")
)
public constructor(navigator: Navigator<out D>, @IdRes id: Int) :
this(navigator, id, null)
/**
* DSL for constructing a new [NavDestination] with a unique route.
*
* This will also update the [id] of the destination based on route.
*
* @param navigator navigator used to create the destination
* @param route the destination's unique route
*
* @return the newly constructed [NavDestination]
*/
public constructor(navigator: Navigator<out D>, route: String?) :
this(navigator, -1, route)
/**
* The descriptive label of the destination
*/
public var label: CharSequence? = null
private var arguments = mutableMapOf<String, NavArgument>()
/**
* Add a [NavArgument] to this destination.
*/
public fun argument(name: String, argumentBuilder: NavArgumentBuilder.() -> Unit) {
arguments[name] = NavArgumentBuilder().apply(argumentBuilder).build()
}
private var deepLinks = mutableListOf<NavDeepLink>()
/**
* Add a deep link to this destination.
*
* In addition to a direct Uri match, the following features are supported:
*
* * Uris without a scheme are assumed as http and https. For example,
* `www.example.com` will match `http://www.example.com` and
* `https://www.example.com`.
* * Placeholders in the form of `{placeholder_name}` matches 1 or more
* characters. The String value of the placeholder will be available in the arguments
* [Bundle] with a key of the same name. For example,
* `http://www.example.com/users/{id}` will match
* `http://www.example.com/users/4`.
* * The `.*` wildcard can be used to match 0 or more characters.
*
* @param uriPattern The uri pattern to add as a deep link
* @see deepLink
*/
public fun deepLink(uriPattern: String) {
deepLinks.add(NavDeepLink(uriPattern))
}
/**
* Add a deep link to this destination.
*
* In addition to a direct Uri match, the following features are supported:
*
* * Uris without a scheme are assumed as http and https. For example,
* `www.example.com` will match `http://www.example.com` and
* `https://www.example.com`.
* * Placeholders in the form of `{placeholder_name}` matches 1 or more
* characters. The String value of the placeholder will be available in the arguments
* [Bundle] with a key of the same name. For example,
* `http://www.example.com/users/{id}` will match
* `http://www.example.com/users/4`.
* * The `.*` wildcard can be used to match 0 or more characters.
*
* @param navDeepLink the NavDeepLink to be added to this destination
*/
public fun deepLink(navDeepLink: NavDeepLinkDslBuilder.() -> Unit) {
deepLinks.add(NavDeepLinkDslBuilder().apply(navDeepLink).build())
}
private var actions = mutableMapOf<Int, NavAction>()
/**
* Adds a new [NavAction] to the destination
*/
@Deprecated(
"Building NavDestinations using IDs with the Kotlin DSL has been deprecated in " +
"favor of using routes. When using routes there is no need for actions."
)
public fun action(actionId: Int, actionBuilder: NavActionBuilder.() -> Unit) {
actions[actionId] = NavActionBuilder().apply(actionBuilder).build()
}
/**
* Build the NavDestination by calling [Navigator.createDestination].
*/
public open fun build(): D {
return navigator.createDestination().also { destination ->
if (route != null) {
destination.route = route
}
if (id != -1) {
destination.id = id
}
destination.label = label
arguments.forEach { (name, argument) ->
destination.addArgument(name, argument)
}
deepLinks.forEach { deepLink ->
destination.addDeepLink(deepLink)
}
actions.forEach { (actionId, action) ->
destination.putAction(actionId, action)
}
}
}
}
/**
* DSL for building a [NavAction].
*/
@NavDestinationDsl
public class NavActionBuilder {
/**
* The ID of the destination that should be navigated to when this action is used
*/
public var destinationId: Int = 0
/**
* The set of default arguments that should be passed to the destination. The keys
* used here should be the same as those used on the [NavDestinationBuilder.argument]
* for the destination.
*
* All values added here should be able to be added to a [android.os.Bundle].
*
* @see NavAction.getDefaultArguments
*/
public val defaultArguments: MutableMap<String, Any?> = mutableMapOf()
private var navOptions: NavOptions? = null
/**
* Sets the [NavOptions] for this action that should be used by default
*/
public fun navOptions(optionsBuilder: NavOptionsBuilder.() -> Unit) {
navOptions = NavOptionsBuilder().apply(optionsBuilder).build()
}
internal fun build() = NavAction(
destinationId, navOptions,
if (defaultArguments.isEmpty())
null
else
bundleOf(*defaultArguments.toList().toTypedArray())
)
}
/**
* DSL for constructing a new [NavArgument]
*/
@NavDestinationDsl
public class NavArgumentBuilder {
private val builder = NavArgument.Builder()
private var _type: NavType<*>? = null
/**
* The NavType for this argument.
*
* If you don't set a type explicitly, it will be inferred
* from the default value of this argument.
*/
public var type: NavType<*>
set(value) {
_type = value
builder.setType(value)
}
get() {
return _type ?: throw IllegalStateException("NavType has not been set on this builder.")
}
/**
* Controls if this argument allows null values.
*/
public var nullable: Boolean = false
set(value) {
field = value
builder.setIsNullable(value)
}
/**
* An optional default value for this argument.
*
* Any object that you set here must be compatible with [type], if it was specified.
*/
public var defaultValue: Any? = null
set(value) {
field = value
builder.setDefaultValue(value)
}
/**
* Builds the NavArgument by calling [NavArgument.Builder.build].
*/
public fun build(): NavArgument {
return builder.build()
}
}