├── inflation-inject-sample ├── shrinker.pro ├── signing.keystore ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ ├── Greeter.java │ │ │ ├── ViewModule.java │ │ │ ├── MainActivity.java │ │ │ └── CustomView.java │ │ ├── AndroidManifest.xml │ │ └── res │ │ └── layout │ │ └── custom_view.xml └── build.gradle ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── gradle-mvn-push.gradle ├── renovate.json ├── .gitignore ├── inflation-inject-processor ├── gradle.properties ├── src │ ├── main │ │ └── java │ │ │ └── app │ │ │ └── cash │ │ │ └── inject │ │ │ └── inflation │ │ │ └── processor │ │ │ ├── internal │ │ │ ├── kotlinStdlib.kt │ │ │ ├── javaPoet.kt │ │ │ ├── generatedAnnotation.kt │ │ │ └── annotationProcessing.kt │ │ │ ├── DependencyRequest.kt │ │ │ ├── Key.kt │ │ │ ├── InflationInjectionModule.kt │ │ │ ├── AssistedInjection.kt │ │ │ └── InflationInjectProcessor.kt │ └── test │ │ └── java │ │ └── app │ │ └── cash │ │ └── inject │ │ └── inflation │ │ └── processor │ │ └── InflationInjectProcessorTest.kt └── build.gradle ├── settings.gradle ├── inflation-inject ├── gradle.properties ├── src │ ├── main │ │ └── java │ │ │ └── app │ │ │ └── cash │ │ │ └── inject │ │ │ └── inflation │ │ │ ├── ViewFactory.java │ │ │ ├── Inflated.java │ │ │ ├── InflationInject.java │ │ │ ├── InflationModule.java │ │ │ └── InflationInjectFactory.java │ └── test │ │ └── java │ │ └── app │ │ └── cash │ │ └── inject │ │ └── inflation │ │ ├── InflationInjectFactoryTest.kt │ │ └── InflationInjectFactory2Test.kt └── build.gradle ├── .github └── workflows │ ├── gradle-wrapper.yaml │ ├── build.yaml │ └── release.yaml ├── gradle.properties ├── RELEASING.md ├── gradlew.bat ├── README.md ├── CHANGELOG.md ├── gradlew └── LICENSE.txt /inflation-inject-sample/shrinker.pro: -------------------------------------------------------------------------------- 1 | -allowaccessmodification 2 | -dontobfuscate 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cashapp/InflationInject/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /inflation-inject-sample/signing.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cashapp/InflationInject/HEAD/inflation-inject-sample/signing.keystore -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build 4 | reports 5 | 6 | # IntelliJ 7 | .idea 8 | *.iml 9 | out 10 | 11 | # Android 12 | local.properties 13 | -------------------------------------------------------------------------------- /inflation-inject-processor/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Inflation Inject Annotation Processor 2 | POM_ARTIFACT_ID=inflation-inject-processor 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'inflation-inject' 2 | 3 | include ':inflation-inject' 4 | include ':inflation-inject-processor' 5 | include ':inflation-inject-sample' 6 | -------------------------------------------------------------------------------- /inflation-inject/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Inflation Inject Runtime 2 | POM_ARTIFACT_ID=inflation-inject 3 | POM_PACKAGING=jar 4 | 5 | kotlin.stdlib.default.dependency=false 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /inflation-inject-sample/src/main/java/com/example/Greeter.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import javax.inject.Inject; 4 | 5 | public final class Greeter { 6 | @Inject Greeter() { 7 | } 8 | 9 | public String sayHi(String name) { 10 | return "Hello, " + name + "!"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /inflation-inject-sample/src/main/java/com/example/ViewModule.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import app.cash.inject.inflation.InflationModule; 4 | import dagger.Module; 5 | 6 | @InflationModule 7 | @Module(includes = InflationInject_ViewModule.class) 8 | public abstract class ViewModule { 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper.yaml: -------------------------------------------------------------------------------- 1 | name: gradle-wrapper 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - 'gradlew' 7 | - 'gradlew.bat' 8 | - 'gradle/wrapper/' 9 | 10 | jobs: 11 | validate: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: gradle/wrapper-validation-action@v1 16 | -------------------------------------------------------------------------------- /inflation-inject-sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /inflation-inject/src/main/java/app/cash/inject/inflation/ViewFactory.java: -------------------------------------------------------------------------------- 1 | package app.cash.inject.inflation; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | /** 10 | * An interface for abstracting the two-argument {@link View} constructor that is used during 11 | * XML-based layout inflation. 12 | */ 13 | public interface ViewFactory { 14 | @NonNull 15 | View create(@NonNull Context context, @Nullable AttributeSet attrs); 16 | } 17 | -------------------------------------------------------------------------------- /inflation-inject/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'org.jetbrains.kotlin.jvm' 3 | 4 | sourceCompatibility = JavaVersion.VERSION_1_6 5 | targetCompatibility = JavaVersion.VERSION_1_6 6 | 7 | dependencies { 8 | compileOnly deps.android 9 | // Annotations are exposed as 'api' because Dagger wants to read the @NonNull annotation on the 10 | // @Inject constructor parameter if you are using its implicit binding. 11 | api deps.androidxAnnotations 12 | api deps.inject 13 | 14 | testImplementation deps.kotlin 15 | testImplementation deps.junit 16 | testImplementation deps.robolectric 17 | testImplementation deps.android 18 | } 19 | 20 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') 21 | -------------------------------------------------------------------------------- /inflation-inject-sample/src/main/java/com/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import app.cash.inject.inflation.InflationInjectFactory; 6 | import dagger.Component; 7 | 8 | public final class MainActivity extends Activity { 9 | @Override protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | 12 | InflationInjectFactory factory = DaggerMainActivity_MainComponent.create().factory(); 13 | getLayoutInflater().setFactory(factory); 14 | 15 | setContentView(R.layout.custom_view); 16 | } 17 | 18 | @Component(modules = ViewModule.class) 19 | interface MainComponent { 20 | InflationInjectFactory factory(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /inflation-inject/src/main/java/app/cash/inject/inflation/Inflated.java: -------------------------------------------------------------------------------- 1 | package app.cash.inject.inflation; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import static java.lang.annotation.ElementType.PARAMETER; 9 | import static java.lang.annotation.RetentionPolicy.CLASS; 10 | 11 | /** 12 | * Denotes the {@link Context} and/or {@link AttributeSet} parameters of an 13 | * {@link InflationInject @InflationInject}-annotated view constructor which are fulfilled by the 14 | * layout inflater rather than the dependency graph. 15 | * 16 | * @see InflationInject 17 | */ 18 | @Retention(CLASS) 19 | @Target(PARAMETER) 20 | public @interface Inflated { 21 | } 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=app.cash.inject 2 | VERSION_NAME=1.1.0-SNAPSHOT 3 | 4 | POM_DESCRIPTION=Constructor-inject views during layout inflation 5 | 6 | POM_URL=https://github.com/cashapp/InflationInjection/ 7 | POM_SCM_URL=https://github.com/cashapp/InflationInjection/ 8 | POM_SCM_CONNECTION=scm:git:git://github.com/cashapp/InflationInjection.git 9 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/cashapp/InflationInjection.git 10 | 11 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 12 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 13 | POM_LICENCE_DIST=repo 14 | 15 | POM_DEVELOPER_ID=cashapp 16 | POM_DEVELOPER_NAME=CashApp 17 | 18 | android.useAndroidX=true 19 | # Disable R8's ProGuard compatibility mode. 20 | android.enableR8.fullMode=true 21 | -------------------------------------------------------------------------------- /inflation-inject-processor/src/main/java/app/cash/inject/inflation/processor/internal/kotlinStdlib.kt: -------------------------------------------------------------------------------- 1 | package app.cash.inject.inflation.processor.internal 2 | 3 | // TODO https://youtrack.jetbrains.com/issue/KT-4734 4 | fun Map.filterNotNullValues(): Map { 5 | @Suppress("UNCHECKED_CAST") 6 | return filterValues { it != null } as Map 7 | } 8 | 9 | /** Equivalent to `this as T` for use in function chains. */ 10 | @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") 11 | inline fun Any.cast(): T = this as T 12 | 13 | @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") 14 | inline fun Iterable<*>.castEach() = map { it as T } 15 | 16 | inline fun T.applyEach(items: Iterable, func: T.(I) -> Unit): T { 17 | items.forEach { item -> func(item) } 18 | return this 19 | } 20 | -------------------------------------------------------------------------------- /inflation-inject-sample/src/main/res/layout/custom_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 |