Skip to content

# Getting started (TBD)

Traditionally, you need to add dependency to your project. Currently, there are two types of artifacts:

- `Core` - only necessary tools for your projects
- `MVVM` - Model-View-ViewModel architecture tools + `Core` components

Artifact | Purpose | Dependency
--- | --- | ---
`Core` | Only necessary tools for your projects | `implementation "dev.inmo:navigation.core:$navigation_version"`
`MVVM` | Model-View-ViewModel architecture tools + `Core` components | `implementation "dev.inmo:navigation.mvvm:$navigation_version"`

# Get started

After you have added your dependency, you should initialize navigation. There are several important things:

1. `Config` - it is an instance of any class which extending the `NavigationNodeDefaultConfig` in common case
2. `Factory` - usually object which may create a node or some required part for node

For example: lets imagine that we have a node `Main`. Here what should we do to create a node and make it workable in navigation:

    data class MainConfig(
        // this id will be used to search an html element by id in JS
        // and Fragment by tag in Android
        override val id: String = "main"
    ) : NavigationNodeDefaultConfig

Both `JS` and `Android` platforms require `ViewModel` for their `MVVM` node variants, but it can be common as well as `MainConfig`:

    class MainViewModel(
        node: NavigationNode<MainConfig, NavigationNodeDefaultConfig>
    ) : ViewModel(
        node
    )

### JS part

    // Core variant without MVVM or Compose
    class MainNode(
        config: MainConfig,
        chain: NavigationChain<NavigationNodeDefaultConfig>,
    ) : JsNavigationNode<MainConfig, NavigationNodeDefaultConfig>(
        chain,
        config
    ) {
        // Some code
        // In htmlElementStateFlow will be found `HTMLElement` where node should be binded
    }
    // MVVM Compose variant
    class MainNodeView(
        config: MainConfig,
        chain: NavigationChain<NavigationNodeDefaultConfig>,
    ) : View<MainConfig, MainViewModel>(
        config,
        chain
    ) {
        // Some code
        // In htmlElementStateFlow will be found `HTMLElement` where node should be binded

        @Composable
        override onDraw() {
            Text("Hello world")
        }
    }

    object MainNodeFactory : NavigationNodeFactory<NavigationNodeDefaultConfig> {
        override fun createNode(
            navigationChain: NavigationChain<NavigationNodeDefaultConfig>,
            config: NavigationNodeDefaultConfig
        ): NavigationNode<out NavigationNodeDefaultConfig, NavigationNodeDefaultConfig>? = if (config is MainConfig) {
            MainNode(config, navigationChain) // Or `MainNodeView(config, chain)` for MVVM
        } else {
            null
        }
    }

Data below is under TBD

### Android

In Android there is one important note: you will not directly work with nodes. In fact it will be required to create special `NodeFragment`:

    // Core variant
    class MainFragment : NodeFragment<MainConfig, NavigationNodeDefaultConfig>() {
        // Your code
        // Here will be available: node with type `AndroidFragmentNode`, config: `MainConfig`
    }
    // MVVM Variant
    class MainViewFragment : ViewFragment<MainViewModel, MainConfig>() {
        // Will be available also `viewModel` via koin `lazyInject`
        override val viewModelClass
            get() = MainViewModel::class
    }

Initialization is different on the platforms, so, lets take a look at each one.

## JS

In `JavaScript` it looks like:

    initNavigation<NavigationNodeDefaultConfig>(
        ConfigHolder.Chain( // (1)
            ConfigHolder.Node( // (2)
                MainConfig(), // (3)
                null, // (4)
                listOf() // (5)
            ),
        ),
        configsRepo = CookiesNavigationConfigsRepo( // (6)
            Json {
                ignoreUnknownKeys = true
                serializersModule = SerializersModule {
                    polymorphic(NavigationNodeDefaultConfig::class, MainConfig::class, MainConfig.serializer()) // (7)
                }
            },
            ConfigHolder.serializer(NavigationNodeDefaultConfig::class.serializer())
        ),
        dropRedundantChainsOnRestore = true, // (8)
        nodesFactory = MainNodeFactory, // (9)
    )

1. Creating of default root chain config holder. It must be root chain because of the chain work with statuses changes
2. Creating of default root node config holder. This type contains config of the first node, its subnode and subchains lists
3. Default root config
4. Subnode of root node. In this case it is `null`, but can be any `ConfigHolder.Node`
5. Subchains of default root node
6. Configurations changes repo saver. By default it is `cookies` (`localStorage`) store
7. Register config for serialization to let configs repo serializer to know how to serialize `MainConfig`
8. Flag that the chains without any node will be dropped automatically
9. In fact here can be factory aggregator, for example:

       val factories: List<NavigationNodeFactory<NavigationNodeDefaultConfig>>
       NavigationNodeFactory<NavigationNodeDefaultConfig> { chainHolder, config ->
           factories.firstNotNullOfOrNull { it.createNode(chainHolder, config) }
       }