Giter Site home page Giter Site logo

nxoim / decomposite Goto Github PK

View Code? Open in Web Editor NEW
9.0 2.0 0.0 66.65 MB

Compose Multiplatform router-style navigation library, based on Decompose, with custom animation system and additional utilities

Home Page: https://decomposite.nxoim.com/docs

License: Apache License 2.0

Shell 0.33% Kotlin 99.48% HTML 0.19%
compose-multiplatform jetpack-compose kotlin kotlin-multiplatform library navigation compose-navigation jetbrains-compose kmm kmm-library

decomposite's Introduction

badge-Android badge-JVM badge-iOS(?) badge-macOS(?) (i dont have apple's devices) Some time in the future WASM/JS and maybe WASI.

What?

Router style navigation library with Decompose used as a base with some features on top, like view model store, overlays, custom extensions like animations, etc.

Why?

There was existing multiplatform tooling, but it was kinda raw for my taste, so I started learning and experimenting by making DSLs based on it and this is the result.

... What was the thought process?

Uhm...

Here's what it has and can do

  • Convenient type-safe router-style navigation
  • Custom animation system (inspired by Decompose)
  • Properly store view models, with configuration change handling, view model scope cancellation and allat
  • Convenient view model instance creation
  • Display destinations in overlays
  • Pass the backstack entry's component context using CompositionLocalProvider
  • Pass the type (contained/overlay) of the displayed content also using CompositionLocalProvider
  • Store navigation controller instances like view models
  • Automatically create navigation controller instances upon the creation of nav hosts that are retrievable by just calling navController, again, kind of like view models

Examples/Getting Started

In your version catalog add the "com.github.nxoim.decomposite:decomposite" artifact. In your toml file that would be:

decomposite = { module = "com.github.nxoim.decomposite:decomposite", version.ref = "version" }

First you have to set up the app by creating a root of the app. This root sets up stores for view models and nav controllers, overlay stuff, and provides the root component context.

On Android:

class YourActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)

        // default component context is included with the decompose library
        val navigationRootData = NavigationRootData(defaultComponentContext())

        setContent {
            NavigationRootProvider(navigationRootData) { YourContent() }
        }
    }
}

Check out the android sample if you want predictive gesture animations application-wide and on older androids.

On everything else:

// outside compose
val navigationRootData = NavigationRootData()

// ...

// inside any composable at the root
NavigationRootProvider(navigationRootData) { YourContent() }

Navigation host creation:

// creating an instance
val yourNavController = navController<YourDestinations>(startingDestination = YourDestinations.Star)

Scaffold(
    bottomBar = { 
		GlobalSampleNavBar(onBack = { yourNavController.navigateBack() }) 
	}
) { scaffoldPadding ->
    NavHost(
        yourNavController,
        Modifier.padding(scaffoldPadding),        
        animations = {
            when (currentChild) {
                RootDestinations.Star -> fade() + scale()
                else -> cleanSlideAndFade()
            }
        }
    ) {
        when (it) { // nested hosts!
            RootDestinations.Star -> StarNavHost()
            RootDestinations.Heart -> HeartNavHost()
        }
    }    
}

Navigation controller usage:

// in any clickable
yourNavController.navigate(YourDestinations.Heart)

// navigate back
yourNavController.navigateBack()

View model creation and usage:

@Composable
fun YourScreen() {
    // get or create a view model
    val vm = viewModel("optional key") { SomeViewModel(someArgument = "some text") }

    // just get a view model. 
    val vm = getExistingViewModel<SomeViewModel>("optional key")
}

class SomeViewModel(someArgument: String) : ViewModel() {
    // you can retain the view model until the app gets destroyed by overriding 
    // onDestroy and not calling removeFromViewModelStore
    override fun onDestroy(removeFromViewModelStore: () -> Unit) {
        // maybe still cancel the scope? maybe
        viewModelScope.coroutineContext.cancelChildren()
    }
}

Back gestures on other platforms:

// this is for jvm
@OptIn(ExperimentalDecomposeApi::class)
fun main() = application {
        // initialize this at the root of your app
        val navigationRootData = NavigationRootData()

        Window(
            title = "Decomposite",
            onCloseRequest = ::exitApplication,
        ) {
            window.minimumSize = Dimension(350, 600)

            SampleTheme {
                // first wrap your app in a theme.
                // because of material 3 quirks - surface wraps the root to fix text
                // colors in overlays.
                Surface {
                    // also since you need to initialize the component context of the app
                    // on your preferred platform anyway - it's ok to add decomposite to
                    // your entry-point/app module of the project, or combine it with your
                    // navigation module

                    // then initialize the back gesture overlay that will handle the back gestures.
                    // initialize it first, put NavigationRoot inside it, else overlays will not
                    // detect the gestures
                    BackGestureProviderContainer(
                        navigationRootData.defaultComponentContext,
                        content = { NavigationRootProvider(navigationRootData) { App() } }
                    )
                }
            }
        }
    }

Or you can apply a modifier to the content you want to handle the back gestures, like:

ExampleComposable(Modifier.backGestureProvider(LocalBackDispatcher.current))

decomposite's People

Contributors

nxoim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.