Giter Club home page Giter Club logo

compass's Introduction

Build Maven Central

Compass

This library offers a KSP API to generate boiler plate code for Jetpack Compose Navigation. It makes allows for a type safe usage of the navigation between Composables and moves potential errors to the compile time. This enables are more robust way of implementing an Android App using Jetpack Compose

Setup

You can get Compass from Maven Central

Latest version: 1.1.0

implementation("de.onecode:compass-api:$compass_version")
implementation("de.onecode:compass-runtime:$compass_version")
ksp("de.onecode:compass-ksp:$compass_version")

Used Kotlin and KSP versions

  • 1.0.0: 1.8.21-1.0.11
  • 1.0.1: 1.8.21-1.0.11
  • 1.1.0: 1.9.22-1.0.16

Usage

  1. Create either Objects or Classes that are annotated with Destination. They can either be bundled in one file or spread across multiple files
  2. Make sure that one Destination is also annotated with Home. This Destination will be the entry point when you start the app.
  3. Compile the app to let KSP generate/update all necessary code from the destination definitions.
  4. A Compass is generated, which you can add to your main Activity/Composable
  5. Check out all provided annotations under API description
@Home
@Destination(name = "Overview")
@Navigation(to = EditorDescription::class)
object OverviewDescription

@Destination(name = "Editor")
@Parameter(name = "clickedItemId", type = Int::class)
object EditorDescription

class MainActivity : ComponentActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContent {
			AppNavGraph()
		}
	}
}

@Composable
fun AppNavGraph() {
	Compass {
		overviewScreen { // generated by KSP
			OverviewScreen( // your content composable for that destination
				onEdit = { clickedItemId ->
					navigateToEditor(clickedItemId) // 'navigateToEditor' is generated by KSP
				}
			)
		}

		editorScreen { // generated by KSP
			EditorScreen() // your content composable for that destination
		}
	}
}

API description

The API of Compass consists of multiple annotations you can use to describe your apps navigation. Annotated destinations can be separate across the app or put together in a single file. Valid targets of all annotations are object, class or interface.

@Destination

The @Destination annotation defines a screen added to a Compose NavHost. You can use the annotation without parameters, in which case the generated code will use the name of the Object or class or you can provide a name in the @Destination annotation

Definition

@Home
@Destination
object SimpleUi

Generates

Compass {
	simpleUiScreen {
		// add your Composables here
	}
}

@Navigation

@Navigation allows you to add routes to another destination. A destination can define as many navigation routes as it wants by simple adding multiple @Navigation annotations. The target of a navigation has to be an Object or Class annotated with @Desination as well.

Definition

@Home
@Destination
@Navigation(to = Second::class)
object First

@Destination
object Second

Generates

Compass {
	firstScreen {
		navigateToSecond()  // generated
	}
	secondScreen {
		// add your Composables here
	}
}

@Parameter

A destination can define parameters it wants to receive when navigated to. The defined parameters will be added to any generated navigation function, targeting the destination.

Supported parameter types are:

  • Numbers, like Int, Long, Double, Float, etc.
  • String

Definition

@Home
@Destination
@Navigation(to = Second::class)
object First

@Destination
@Parameter(name = "someNumber", type = Int::class)
object Second

Generates

Compass {
	firstScreen {
		navigateToSecond(someNumber = 10)  // generated with the specified parameter of destination Second
	}
	secondScreen {
		// add your Composables here
	}
}

@Home

@Home marks a destination as the start destination of the navigation graph or the subgraph. It will be the first destination opened on start up.

@Top

@Top marks a destination to be navigable from the root. This can be useful if your app has a bottom navigation in its root screen. Navigation methods for @Top destinations are generated in the CompoassController. To access the CompassController use rememberCompassController(). @Top annotations are only supported in the main graph, they are disallowed in a sub graph. Important: Don't forget to pass it to the Compass again, to make sure the same instance is used by you and the Compass

@SubGraph

In addition to a main graph which will generate the Compass, destinations can also be grouped together into a subgraph. The subgraph can be defined independently and later included into an existing Compass. This is e.g. useful in multi module projects or for defining something like a wizard.

Definition

@Home
@Destination
@Navigation(to = Second::class)
object FirstSub

@Destination
@Parameter(name = "someNumber", type = Int::class)
object SecondSub

@SubGraph(
	name = "Wizard",
	FirstSub::class,
	SecondSub::class
)
object Module

Generates

wizardSubGraph {
	firstSubScreen {
		navigateToSecond(someNumber = 10)  // generated with the specified parameter of destination SecondSub
	}
	secondSubScreen {
		// add your Composables here
	}
}

wizardSubGraph is an extension function of NavGraphBuilder and can therefore be directly embedded into the Compass lambda.

Home or no home

You can use Compass in two modes for code generation of @Destination (without sub graphs). It is possible to use destinations in a module with and without a @Home navigation. The API described so far was assuming the mode that always one destination is annotated with @Home. This leads to generation of a Compass adding all the destinations the module to it.

You can also use a mode where no @Home destination is defined. In this case no Compass will be generated for you. Instead an extension function to a NavGraphBuilder will be created, that can be used to manually add the destination to either a Compass or a NavHost. This can be useful if you want to structure your destinations in modules without using a sub graph.

Definition

@Destination
object NoHome

Generates

public fun NavGraphBuilder.noHomeScreen(composable: @Composable noHomeContext.() -> Unit){
    ...
}

Usage in e.g. app

Compass { navGraphBuilder ->
	navGraphBuilder.noHomeScreen {
		// Composable
	}
}

You can see an example of this in the destination-feature module

Example

A detailed example on how to you a Compass can be found in the demo app, the demo library contains a configuration for a sub graph and destination-feature contains an example of the no home usage of destinations.

compass's People

Contributors

a-frank avatar florian-meyer-onecode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

compass's Issues

Find a way to support encapsulated multimodule setup

Currently the whole navigation must be defined within the app module.
To loosen coupling between the app module and possible feature modules, it would be nice if each feature module could define its Navigation properties. This is currently not possible - mainly, because the library would expect each feature module to define 1 @Home annotation.

So the idea would be:

  1. Define all Destinations of a feature within its module
  2. Collect all Destinations in the app module and allow it to construct the full navigation logic from that

Add full type-safety for arguments, so they can also be used by savedStateHandle

Currently, if I want to use a Long navigation argument via the savedStateHandle, this does not work in the ViewModel:

checkNotNull(savedStateHandle.get<Long>("sessionId"))

To support the type cast to Long, the navigation composable needs the type info of the argument added to the generated code.
Probably somewhere here: https://github.com/OneCodeDevs/navigator/blob/main/compose-navigator-ksp/src/main/kotlin/de/onecode/navigator/ksp/generator/navigation/AddComposablesBody.kt

Rename Navigator to Compass

To navigate safely you need a reliable tool.
To reflect that better, we rename the library to Compass

Compass = Compose Compass

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.