Skip to content

Commit

Permalink
Merge pull request #7 from LDRAlighieri/feature/carbon
Browse files Browse the repository at this point in the history
Add Carbon annotation processor
  • Loading branch information
LDRAlighieri committed Dec 26, 2023
2 parents b68b126 + 353082d commit c9a03bd
Show file tree
Hide file tree
Showing 39 changed files with 1,282 additions and 104 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Please consider giving this repository a star ⭐ if you like the project.


## Modules
* [composites-carbon] — Annotation processor for generating Route objects that help with navigation based on the Navigation Component
* [composites-fiberglass] — A tool for building complex screens based on simple blocks.


Expand Down Expand Up @@ -88,5 +89,6 @@ limitations under the License.
[compose]: https://developer.android.com/jetpack/compose
[compose-these-composites]: https://medium.com/@ldralighieri/compose-these-composites-8ea923e4a34c
[reach-out-to-infinity]: https://medium.com/@ldralighieri/reach-out-to-infinity-bba17019a938
[composites-carbon]: https://github.com/LDRAlighieri/Composites/tree/main/composites-carbon
[composites-fiberglass]: https://github.com/LDRAlighieri/Composites/tree/main/composites-fiberglass
[performance]: https://developer.android.com/jetpack/compose/performance#build-release
6 changes: 6 additions & 0 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.spotless.gradlePlugin)
compileOnly(libs.ksp.gradlePlugin)
implementation(libs.dokka.gradlePlugin)
}

Expand All @@ -53,6 +54,11 @@ gradlePlugin {
implementationClass = "DokkaConventionPlugin"
}

register("ksp") {
id = "composites.ksp"
implementationClass = "KspConventionPlugin"
}

register("libraryCompose") {
id = "composites.library.compose"
implementationClass = "LibraryComposeConventionPlugin"
Expand Down
27 changes: 27 additions & 0 deletions build-logic/convention/src/main/kotlin/KspConventionPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2023 Vladimir Raupov
*
* 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.
*/

import org.gradle.api.Plugin
import org.gradle.api.Project

@Suppress("unused")
class KspConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.google.devtools.ksp")
}
}
}
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.spotless) apply false
alias(libs.plugins.maven.publish) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.binary.compatibility.validator)
alias(libs.plugins.gver)
}
Expand Down
132 changes: 132 additions & 0 deletions composites-carbon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@

# Carbon

Annotation processor ([Kotlin Symbol Processing, KSP][ksp]) for generating Route objects that help with navigation based on the [Navigation Component][navigation].
Allows you to significantly reduce routine and time spent on creating `Route` objects manually.


## Roadmap

- [X] KSP `Route` object generation
- [ ] Default arguments
- [ ] Enums and Parcelable support (using parcelable is not best practice. It is recommended to use primitives)****


## Using in your projects

Add dependency:

```kotlin
dependencies {
implementation("ru.ldralighieri.composites:composites-carbon-core:0.4.0-SNAPSHOT")
ksp("ru.ldralighieri.composites:composites-carbon-processor:0.4.0-SNAPSHOT")
}
```

Make sure that you have `mavenCentral()` in the list of repositories:

```kotlin
repositories {
mavenCentral()
}
```


## Example

The arguments class/object is the basis for generating the Route object:
```kotlin
@CarbonRoute(route = "composites/fiberglass", deeplinkSchema = "composites")
data class CompositesFiberglassArgs(
val title: String
)
```
The generator currently only supports primitives and strings as arguments.

The generated `Route` object will look as follows:
```kotlin
public object CompositesFiberglassRoute {
public const val route: String = "composites/fiberglass/{title}"

public val arguments: List<NamedNavArgument> = listOf(
navArgument("title") {
type = StringType
nullable = false
},
)

public val deepLinks: List<NavDeepLink> = listOf(
navDeepLink {
uriPattern = "composites://$route"
}
)

public fun create(title: String): Destination.Compose =
Destination.Compose("composites/fiberglass/$title")

public fun parseArguments(backStackEntry: NavBackStackEntry): CompositesFiberglassArgs =
CompositesFiberglassArgs(
title = backStackEntry.arguments?.getString("title") ?: "",
)

public fun parseArguments(savedStateHandle: SavedStateHandle): CompositesFiberglassArgs =
CompositesFiberglassArgs(
title = savedStateHandle["title"] ?: "",
)
}
```
The object contains the components necessary for navigation:
- `route`, `arguments` and `deeplink` are used for navigation
- `parseArguments` and `parseArguments` for parsing the argument class from `NavBackStackEntry` and `SavedStateHandle` respectively
- `create` creates a Destination class for [navigator]

If the base object contains no arguments:
```kotlin
@CarbonRoute(route = "composites")
data object CompositesArgs
```

Then the generated `Route` object will not contain `parseArguments` and `parseArguments` methods:
```kotlin
public object CompositesRoute {
public const val route: String = "composites"

public val arguments: List<NamedNavArgument> = emptyList()

public val deepLinks: List<NavDeepLink> = emptyList()

public fun create(): Destination.Compose = Destination.Compose("composites")
}
```

Using a simple [navigator], you can implement navigation based on the Route object:
```kotlin
LazyColumn {
item(key = "fiberglass") {
CompositeItem(
title = "Fiberglass",
onClick = {
navigator.navigateTo(
CompositesFiberglassRoute.create(title = "Fiberglass composites")
)
}
)
}
}

composable(
route = CompositesFiberglassRoute.route,
arguments = CompositesFiberglassRoute.arguments,
deepLinks = CompositesFiberglassRoute.deepLinks,
) { navBackStackEntry ->
FiberglassRootScreen(args = CompositesFiberglassRoute.parseArguments(navBackStackEntry))
}
```

A more complex example can be found in the [demo application][demo]


[ksp]: https://kotlinlang.org/docs/ksp-overview.html
[navigator]: https://github.com/LDRAlighieri/Composites/blob/master/sample/src/main/kotlin/ru/ldralighieri/composites/sample/navigation/Navigator.kt
[navigation]: https://developer.android.com/guide/navigation
[demo]: https://github.com/LDRAlighieri/Composites/blob/master/sample/src/main/kotlin/ru/ldralighieri/composites/sample/navigation/AppNavHost.kt
1 change: 1 addition & 0 deletions composites-carbon/core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
59 changes: 59 additions & 0 deletions composites-carbon/core/api/core.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
public final class ru/ldralighieri/composites/carbon/core/ArgumentData {
public fun <init> (Ljava/lang/String;Lcom/squareup/kotlinpoet/TypeName;Z)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lcom/squareup/kotlinpoet/TypeName;
public final fun component3 ()Z
public final fun copy (Ljava/lang/String;Lcom/squareup/kotlinpoet/TypeName;Z)Lru/ldralighieri/composites/carbon/core/ArgumentData;
public static synthetic fun copy$default (Lru/ldralighieri/composites/carbon/core/ArgumentData;Ljava/lang/String;Lcom/squareup/kotlinpoet/TypeName;ZILjava/lang/Object;)Lru/ldralighieri/composites/carbon/core/ArgumentData;
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public final fun getTypeName ()Lcom/squareup/kotlinpoet/TypeName;
public fun hashCode ()I
public final fun isNullable ()Z
public fun toString ()Ljava/lang/String;
}

public abstract interface annotation class ru/ldralighieri/composites/carbon/core/CarbonRoute : java/lang/annotation/Annotation {
public abstract fun deeplinkSchema ()Ljava/lang/String;
public abstract fun route ()Ljava/lang/String;
}

public final class ru/ldralighieri/composites/carbon/core/CarbonRouteData {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/squareup/kotlinpoet/ClassName;Ljava/lang/String;Ljava/util/List;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()Lcom/squareup/kotlinpoet/ClassName;
public final fun component5 ()Ljava/lang/String;
public final fun component6 ()Ljava/util/List;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/squareup/kotlinpoet/ClassName;Ljava/lang/String;Ljava/util/List;)Lru/ldralighieri/composites/carbon/core/CarbonRouteData;
public static synthetic fun copy$default (Lru/ldralighieri/composites/carbon/core/CarbonRouteData;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/squareup/kotlinpoet/ClassName;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lru/ldralighieri/composites/carbon/core/CarbonRouteData;
public fun equals (Ljava/lang/Object;)Z
public final fun getArguments ()Ljava/util/List;
public final fun getClassName ()Lcom/squareup/kotlinpoet/ClassName;
public final fun getDeeplinkSchema ()Ljava/lang/String;
public final fun getFileName ()Ljava/lang/String;
public final fun getPackageName ()Ljava/lang/String;
public final fun getRoute ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract interface annotation class ru/ldralighieri/composites/carbon/core/DefaultValue : java/lang/annotation/Annotation {
public abstract fun value ()Ljava/lang/String;
}

public abstract interface class ru/ldralighieri/composites/carbon/core/Destination {
}

public final class ru/ldralighieri/composites/carbon/core/Destination$Compose : ru/ldralighieri/composites/carbon/core/Destination {
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;)Lru/ldralighieri/composites/carbon/core/Destination$Compose;
public static synthetic fun copy$default (Lru/ldralighieri/composites/carbon/core/Destination$Compose;Ljava/lang/String;ILjava/lang/Object;)Lru/ldralighieri/composites/carbon/core/Destination$Compose;
public fun equals (Ljava/lang/Object;)Z
public final fun getRoute ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

24 changes: 24 additions & 0 deletions composites-carbon/core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 Vladimir Raupov
*
* 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.
*/

plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.maven.publish)
}

dependencies {
implementation(libs.kotlinpoet.jvm)
}
20 changes: 20 additions & 0 deletions composites-carbon/core/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#
# Copyright 2023 Vladimir Raupov
#
# 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.
#

POM_ARTIFACT_ID=composites-carbon-core
POM_NAME=Composites (carbon-core)
POM_DESCRIPTION=Core models for the Carbon annotation processor
POM_PACKAGING=aar
21 changes: 21 additions & 0 deletions composites-carbon/core/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2023 Vladimir Raupov
*
* 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 ru.ldralighieri.composites.carbon.core

@Target(AnnotationTarget.CLASS)
annotation class CarbonRoute(val route: String, val deeplinkSchema: String = "")

// TODO The default value cannot be defined via KSP, so we will need to explicitly specify the
// value via this annotation
@Target(AnnotationTarget.VALUE_PARAMETER)
annotation class DefaultValue(val value: String)
Loading

0 comments on commit c9a03bd

Please sign in to comment.