Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to using a processor based off the one currently in circuit-code-gen #1

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

124 changes: 124 additions & 0 deletions .idea/uiDesigner.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ allprojects {
plugins {
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.ktlint) apply true
alias(libs.plugins.ksp) apply false
alias(libs.plugins.mavenpublish) apply false
}
7 changes: 7 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[versions]
anvil = "2.4.8"
app-cash-sqldelight = "2.0.0"
circuit = "0.17.0"
dagger = "2.49"
io-ktor = "2.3.6"
kotlinInject = "0.6.3"
kotlinpoet = "1.15.2"
Expand All @@ -12,7 +14,12 @@ plugin-ktlint = "11.3.2"
plugin-mavenpublish = "0.21.0"

[libraries]
anvil-annotations = { module = "com.squareup.anvil:annotations", version.ref = "anvil" }
autoService-annotations = { module = "com.google.auto.service:auto-service-annotations", version = "1.1.1" }
autoService-ksp = { module = "dev.zacsweers.autoservice:auto-service-ksp", version = "1.1.0" }
circuit-codegen-annotations = { module = "com.slack.circuit:circuit-codegen-annotations", version.ref = "circuit" }
circuit-foundation = { module = "com.slack.circuit:circuit-foundation", version.ref = "circuit" }
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
kotlin-inject-compiler-ksp = { module = "me.tatarka.inject:kotlin-inject-compiler-ksp", version.ref = "kotlinInject" }
kotlin-inject-runtime = { module = "me.tatarka.inject:kotlin-inject-runtime", version.ref = "kotlinInject" }
kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" }
Expand Down
1 change: 1 addition & 0 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ dependencies {
ksp {
arg("circuit.codegen.package", "com.joshafeinberg.circuitkotlininject.sample")
arg("circuit.codegen.parent.component", "com.joshafeinberg.circuitkotlininject.sample.ParentComponent")
arg("circuit.codegen.mode", "kotlin_inject")
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.joshafeinberg.circuitkotlininject.processors.annotations.CircuitInject
import com.slack.circuit.foundation.CircuitCompositionLocals
import com.slack.circuit.foundation.CircuitContent
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import me.tatarka.inject.annotations.Scope

fun main() = application {
val parentComponent = remember { ParentComponent::class.create() }
Expand All @@ -40,7 +40,10 @@ abstract class ParentComponent {

}

@CircuitInject(MyScreen::class, MyScreen.MyScreenState::class)
@Scope
annotation class AppScope

@com.slack.circuit.codegen.annotations.CircuitInject(MyScreen::class, AppScope::class)
@Composable
fun MyScreen(state: MyScreen.MyScreenState, modifier: Modifier) {
Text(state.visibleString)
Expand All @@ -54,8 +57,11 @@ data object MyScreen : Screen {

}

@CircuitInject(MyScreen::class, MyScreen.MyScreenState::class)
class MyScreenPresenter(private val injectedString: String) : Presenter<MyScreen.MyScreenState> {
@com.slack.circuit.codegen.annotations.CircuitInject(MyScreen::class, AppScope::class)
class MyScreenPresenter(
private val injectedString: String,
private val screen: MyScreen,
) : Presenter<MyScreen.MyScreenState> {
@Composable
override fun present(): MyScreen.MyScreenState {
return MyScreen.MyScreenState(injectedString)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.joshafeinberg.circuitkotlininject.sample.other

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.joshafeinberg.circuitkotlininject.sample.AppScope
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen

@com.slack.circuit.codegen.annotations.CircuitInject(OtherScreen::class, AppScope::class)
@Composable
fun OtherScreen(modifier: Modifier) {
Text("Other Screen")
}

data object OtherScreen : Screen {

data object OtherScreenState : CircuitUiState

}

@com.slack.circuit.codegen.annotations.CircuitInject(OtherScreen::class, AppScope::class)
class OtherScreenPresenter : Presenter<OtherScreen.OtherScreenState> {
@Composable
override fun present(): OtherScreen.OtherScreenState {
return OtherScreen.OtherScreenState
}

}
1 change: 1 addition & 0 deletions ui-injector-annotations/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ kotlin {
commonMain {
dependencies {
compileOnly(libs.circuit.foundation)
// api(libs.circuit.codegen.annotations)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,130 @@
package com.joshafeinberg.circuitkotlininject.annotations
// Copyright (C) 2022 Slack Technologies, LLC
// SPDX-License-Identifier: Apache-2.0
package com.slack.circuit.codegen.annotations

import androidx.compose.runtime.Composable
import com.slack.circuit.foundation.Circuit
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen
import com.slack.circuit.runtime.ui.Ui
import kotlin.reflect.KClass

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
annotation class CircuitInject(val screen: KClass<out Screen>, val state: KClass<out CircuitUiState>)
/**
* This annotation is used to mark a UI or presenter class or function for code generation. When
* annotated, the type's corresponding factory will be generated and keyed with the defined [screen]
* .
*
* The generated factories are then contributed to Anvil via
* [com.squareup.anvil.annotations.ContributesMultibinding] and scoped with the provided [scope]
* key.
*
* ## Classes
*
* [Presenter] and [Ui] classes can be annotated and have their corresponding [Presenter.Factory] or
* [Ui.Factory] classes generated for them.
*
* **Presenter**
*
* ```kotlin
* @CircuitInject(HomeScreen::class, AppScope::class)
* class HomePresenter @Inject constructor(...) : Presenter<HomeState> { ... }
*
* // Generates
* @ContributesMultibinding(AppScope::class)
* class HomePresenterFactory @Inject constructor() : Presenter.Factory { ... }
* ```
*
* **UI**
*
* ```kotlin
* @CircuitInject(HomeScreen::class, AppScope::class)
* class HomeUi @Inject constructor(...) : Ui<HomeState> { ... }
*
* // Generates
* @ContributesMultibinding(AppScope::class)
* class HomeUiFactory @Inject constructor() : Ui.Factory { ... }
* ```
*
* ## Functions
*
* Simple functions can be annotated and have a corresponding [Presenter.Factory] generated. This is
* primarily useful for simple cases where a class is just technical tedium.
*
* **Requirements**
* - Presenter function names _must_ end in `Presenter`, otherwise they will be treated as UI
* functions.
* - Presenter functions _must_ return a [CircuitUiState] type.
* - UI functions can optionally accept a [CircuitUiState] type as a parameter, but it is not
* required.
* - UI functions _must_ return [Unit].
* - Both presenter and UI functions _must_ be [Composable].
*
* **Presenter**
*
* ```kotlin
* @CircuitInject(HomeScreen::class, AppScope::class)
* @Composable
* fun HomePresenter(): HomeState { ... }
*
* // Generates
* @ContributesMultibinding(AppScope::class)
* class HomePresenterFactory @Inject constructor() : Presenter.Factory { ... }
* ```
*
* **UI**
*
* ```kotlin
* @CircuitInject(HomeScreen::class, AppScope::class)
* @Composable
* fun Home(state: HomeState) { ... }
*
* // Generates
* @ContributesMultibinding(AppScope::class)
* class HomeUiFactory @Inject constructor() : Ui.Factory { ... }
* ```
*
* ## Assisted injection
*
* Any type that is offered in [Presenter.Factory] and [Ui.Factory] can be offered as an assisted
* injection to types using Dagger [dagger.assisted.AssistedInject]. For these cases, the
* [dagger.assisted.AssistedFactory] -annotated interface should be annotated with [CircuitInject]
* instead of the enclosing class.
*
* Types available for assisted injection are:
* - [Screen] – the screen key used to create the [Presenter] or [Ui].
* - [Navigator] – (presenters only)
* - [Circuit]
*
* Each should only be defined at-most once.
*
* **Examples**
*
* ```kotlin
* // Function example
* @CircuitInject(HomeScreen::class, AppScope::class)
* @Composable
* fun HomePresenter(screen: Screen, navigator: Navigator): HomeState { ... }
*
* // Class example
* class HomePresenter @AssistedInject constructor(
* @Assisted screen: Screen,
* @Assisted navigator: Navigator,
* ...
* ) : Presenter<HomeState> {
* // ...
*
* @CircuitInject(HomeScreen::class, AppScope::class)
* @AssistedFactory
* fun interface Factory {
* fun create(screen: Screen, navigator: Navigator): HomePresenter
* }
* }
* ```
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
public annotation class CircuitInject(
val screen: KClass<out Screen>,
val scope: KClass<*>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.joshafeinberg.circuitkotlininject.annotations

import com.slack.circuit.runtime.screen.Screen
import kotlin.reflect.KClass

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
annotation class CircuitInjectOld(val screen: KClass<out Screen>)
Loading