From 98d1597157e296ee73d2f118b300cde6ebabb9c6 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Mon, 8 May 2023 23:53:24 +0530 Subject: [PATCH] feat(templates): add base configuration for creating templates --- .idea/compiler.xml | 3 + templates-api/build.gradle.kts | 13 +- .../base/AndroidModuleTemplateBuilder.kt | 17 +++ .../templates/base/ModuleTemplateBuilder.kt | 34 +++-- .../base/modules/android/buildGradle.kt | 137 ++++++++++-------- .../templates/base/modules/common.kt | 3 + .../{JavaSourceBuilder.kt => SourceWriter.kt} | 87 +++++++++-- .../androidide/templates/base/util/utils.kt | 11 +- templates-impl/build.gradle.kts | 12 +- .../emptyActivity/emptyActivityTemplate.kt | 70 ++++++++- .../templates/TemplateBuilderTest.kt | 26 +++- .../templates/TestRecipeExecutor.kt | 5 +- .../itsaky/androidide/templates/UtilTest.kt | 0 .../com/itsaky/androidide/templates/utils.kt | 15 +- 14 files changed, 313 insertions(+), 120 deletions(-) rename templates-api/src/main/java/com/itsaky/androidide/templates/base/util/{JavaSourceBuilder.kt => SourceWriter.kt} (56%) rename {templates-api => templates-impl}/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt (83%) rename {templates-api => templates-impl}/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt (88%) rename {templates-api => templates-impl}/src/test/java/com/itsaky/androidide/templates/UtilTest.kt (100%) rename {templates-api => templates-impl}/src/test/java/com/itsaky/androidide/templates/utils.kt (85%) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 15a57a48b..e027f9230 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -124,6 +124,9 @@ + + + diff --git a/templates-api/build.gradle.kts b/templates-api/build.gradle.kts index 058892325..c47c06d46 100644 --- a/templates-api/build.gradle.kts +++ b/templates-api/build.gradle.kts @@ -32,15 +32,8 @@ dependencies { implementation(projects.resources) implementation(projects.subprojects.xmlUtils) - implementation(libs.androidx.annotation) implementation(libs.aapt2.common) - - testImplementation(projects.lsp.api) - testImplementation(projects.preferences) - testImplementation(projects.shared) - testImplementation(libs.tests.androidx.test.core) - testImplementation(libs.tests.google.truth) - testImplementation(libs.tests.junit) - testImplementation(libs.tests.mockk) - testImplementation(libs.tests.robolectric) + implementation(libs.androidx.annotation) + implementation(libs.androidx.appcompat) + implementation(libs.google.material) } \ No newline at end of file diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/AndroidModuleTemplateBuilder.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/AndroidModuleTemplateBuilder.kt index db1780dfc..ec27a2fa2 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/AndroidModuleTemplateBuilder.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/AndroidModuleTemplateBuilder.kt @@ -24,6 +24,7 @@ import com.itsaky.androidide.templates.SrcSet import com.itsaky.androidide.templates.base.modules.android.buildGradleSrc import com.itsaky.androidide.templates.base.modules.android.proguardRules import com.itsaky.androidide.templates.base.util.AndroidManifestBuilder +import com.squareup.javapoet.TypeSpec import java.io.File class AndroidModuleTemplateBuilder : ModuleTemplateBuilder() { @@ -69,6 +70,22 @@ class AndroidModuleTemplateBuilder : ModuleTemplateBuilder() { copyAssetsRecursively(baseAsset("res"), mainResDir()) } + /** + * Creates a new activity class in the application/library package. + * + * @param name The name of the class. + */ + fun RecipeExecutor.createActivity(name: String = "MainActivity", + configure: TypeSpec.Builder.() -> Unit + ) { + sources { + createClass(data.packageName, name) { + + configure() + } + } + } + override fun baseAsset(path: String): String { return super.baseAsset("android/${path}") } diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/ModuleTemplateBuilder.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/ModuleTemplateBuilder.kt index 8cb9b42b7..001840fc7 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/ModuleTemplateBuilder.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/ModuleTemplateBuilder.kt @@ -17,6 +17,7 @@ package com.itsaky.androidide.templates.base +import com.itsaky.androidide.templates.Language import com.itsaky.androidide.templates.ModuleTemplate import com.itsaky.androidide.templates.ModuleTemplateData import com.itsaky.androidide.templates.RecipeExecutor @@ -25,8 +26,7 @@ import com.itsaky.androidide.templates.TemplateBuilder import com.itsaky.androidide.templates.TemplateRecipe import com.itsaky.androidide.templates.base.models.Dependency import com.itsaky.androidide.templates.base.models.defaultDependency -import com.itsaky.androidide.templates.base.modules.android.proguardRules -import com.itsaky.androidide.templates.base.util.JavaSourceBuilder +import com.itsaky.androidide.templates.base.util.SourceWriter import java.io.File /** @@ -39,7 +39,7 @@ abstract class ModuleTemplateBuilder : ExecutorDataTemplateBuilder() { internal val dependencies = hashSetOf() - protected val javaSourceBuilder = JavaSourceBuilder() + protected val sourceWriter = SourceWriter() internal var _name: String? = null val name: String @@ -54,7 +54,8 @@ abstract class ModuleTemplateBuilder : * @param path The path for the asset. * @see com.itsaky.androidide.templates.base.baseAsset */ - open fun baseAsset(path: String) = com.itsaky.androidide.templates.base.util.baseAsset("module", path) + open fun baseAsset(path: String) = + com.itsaky.androidide.templates.base.util.baseAsset("module", path) /** * Get the `build.gradle[.kts]` file for this module.l @@ -63,6 +64,18 @@ abstract class ModuleTemplateBuilder : return data.buildGradleFile() } + /** + * Get the path to the Java source file in the given [source set][srcSet] with the + * given [packageName] and the [simple name][name]. + */ + fun srcFilePath(srcSet: SrcSet, packageName: String, name: String, language: Language): File { + var path = packageName.replace('.', '/') + path += "/${name}" + path += ".${language.ext}" + + return File(javaSrc(srcSet), path) + } + /** * Get the `java` sources directory for the [SrcSet.Main] source set. */ @@ -101,12 +114,12 @@ abstract class ModuleTemplateBuilder : } /** - * Configure the Java source files for this module. + * Configure the source files for this module. * - * @param configure Function for configuring the Java source files. + * @param configure Function for configuring the source files. */ - fun java(configure: JavaSourceBuilder.() -> Unit) { - javaSourceBuilder.apply(configure) + fun sources(configure: SourceWriter.() -> Unit) { + sourceWriter.apply(configure) } /** @@ -141,11 +154,6 @@ abstract class ModuleTemplateBuilder : */ fun commonPostRecipe(extraConfig: TemplateRecipe = {}): TemplateRecipe = { - // Write the java source files - javaSourceBuilder.apply { - write() - } - // Write build.gradle[.kts] buildGradle() diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt index c2eeaf73e..92a2e4eef 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt @@ -17,6 +17,7 @@ package com.itsaky.androidide.templates.base.modules.android +import com.itsaky.androidide.templates.Language import com.itsaky.androidide.templates.ModuleType import com.itsaky.androidide.templates.base.AndroidModuleTemplateBuilder import com.itsaky.androidide.templates.base.modules.dependencies @@ -34,81 +35,95 @@ fun AndroidModuleTemplateBuilder.buildGradleSrc(): String { private fun AndroidModuleTemplateBuilder.buildGradleSrcKts(): String { return """ plugins { - id("$androidPlugin") - } + id("$androidPlugin") + ${ktPlugin()} +} - android { - compileSdkVersion(${data.versions.compileSdk.api}) - buildToolsVersion = "${data.versions.buildTools}" +android { + compileSdkVersion(${data.versions.compileSdk.api}) + buildToolsVersion = "${data.versions.buildTools}" + + defaultConfig { + applicationId = "${data.packageName}" + minSdk = ${data.versions.minSdk.api} + targetSdk = ${data.versions.targetSdk.api} + versionCode = 1 + versionName = "1.0" + } - defaultConfig { - applicationId = "${data.packageName}" - minSdk = ${data.versions.minSdk.api} - targetSdk = ${data.versions.targetSdk.api} - versionCode = 1 - versionName = "1.0" - } - - compileOptions { - sourceCompatibility ${data.versions.javaSource()} - targetCompatibility ${data.versions.javaTarget()} - } - - buildTypes { - release { - isMinifyEnabled = true - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - } - } - - buildFeatures { - viewBinding true + compileOptions { + sourceCompatibility ${data.versions.javaSource()} + targetCompatibility ${data.versions.javaTarget()} + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } - ${dependencies()} + buildFeatures { + viewBinding true + } +} - """.trimIndent() +${dependencies()} +""" } private fun AndroidModuleTemplateBuilder.buildGradleSrcGroovy(): String { return """ - plugins { - id '$androidPlugin' +plugins { + id '$androidPlugin' + ${ktPlugin()} +} + +android { + compileSdk ${data.versions.compileSdk.api} + buildToolsVersion "${data.versions.buildTools}" + + defaultConfig { + applicationId "com.itsaky.myapplication" + minSdk ${data.versions.minSdk.api} + targetSdk ${data.versions.targetSdk.api} + versionCode 1 + versionName "1.0" } - android { - compileSdk ${data.versions.compileSdk.api} - buildToolsVersion "${data.versions.buildTools}" - - defaultConfig { - applicationId "com.itsaky.myapplication" - minSdk ${data.versions.minSdk.api} - targetSdk ${data.versions.targetSdk.api} - versionCode 1 - versionName "1.0" - } - - buildTypes { - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility ${data.versions.javaSource()} - targetCompatibility ${data.versions.javaTarget()} - } - - buildFeatures { - viewBinding true + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - dependencies { - + compileOptions { + sourceCompatibility ${data.versions.javaSource()} + targetCompatibility ${data.versions.javaTarget()} } - """.trimIndent() -} \ No newline at end of file + buildFeatures { + viewBinding true + } +} + +${dependencies()} +""" +} + +private fun AndroidModuleTemplateBuilder.ktPlugin(): String { + if (data.language != Language.Kotlin) { + return "" + } + + return if (data.useKts) ktPluginKts() else ktPluginGroovy() +} + +private fun ktPluginKts(): String { + return """id("kotlin-android")""" +} + +private fun ktPluginGroovy(): String { + return "id 'kotlin-android'" +} diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/common.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/common.kt index fe6edae28..28417fd03 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/common.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/common.kt @@ -31,9 +31,12 @@ internal fun ModuleTemplateBuilder.dependencies(): String { return StringBuilder().apply { append("dependencies {") + append(System.lineSeparator()) for (dep in dependencies) { + append(System.lineSeparator()) append(" ${dep.value()}") } + append(System.lineSeparator()) append("}") }.toString() } diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/JavaSourceBuilder.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/SourceWriter.kt similarity index 56% rename from templates-api/src/main/java/com/itsaky/androidide/templates/base/util/JavaSourceBuilder.kt rename to templates-api/src/main/java/com/itsaky/androidide/templates/base/util/SourceWriter.kt index b9a5a7b2a..2f33ba339 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/JavaSourceBuilder.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/SourceWriter.kt @@ -17,6 +17,8 @@ package com.itsaky.androidide.templates.base.util +import com.itsaky.androidide.templates.Language +import com.itsaky.androidide.templates.SrcSet import com.itsaky.androidide.templates.base.ModuleTemplateBuilder import com.squareup.javapoet.ClassName import com.squareup.javapoet.JavaFile @@ -24,11 +26,11 @@ import com.squareup.javapoet.TypeSpec import jdkx.lang.model.element.Modifier /** - * Utility for building Java source files. + * Utility for building/writing source files. * * @author Akash Yadav */ -class JavaSourceBuilder { +class SourceWriter { /** * The type of Java source. A [SourceType] creates a [TypeSpec.Builder] and optionally @@ -82,8 +84,6 @@ class JavaSourceBuilder { } } - private val files = hashSetOf() - /** * Creates a new Java class. * @@ -91,7 +91,9 @@ class JavaSourceBuilder { * @param className The name of the class. * @param configure Function to configure the [TypeSpec.Builder]. */ - fun createClass(packageName: String, className: String, configure: TypeSpec.Builder.() -> Unit) { + fun ModuleTemplateBuilder.createClass(packageName: String, className: String, + configure: TypeSpec.Builder.() -> Unit + ) { return createJavaFile(packageName, className, ClassType(), configure) } @@ -102,7 +104,9 @@ class JavaSourceBuilder { * @param className The name of the class. * @param configure Function to configure the [TypeSpec.Builder]. */ - fun createEnum(packageName: String, className: String, configure: TypeSpec.Builder.() -> Unit) { + fun ModuleTemplateBuilder.createEnum(packageName: String, className: String, + configure: TypeSpec.Builder.() -> Unit + ) { return createJavaFile(packageName, className, EnumType(), configure) } @@ -113,7 +117,8 @@ class JavaSourceBuilder { * @param className The name of the interface. * @param configure Function to configure the [TypeSpec.Builder]. */ - fun createInterface(packageName: String, className: String, configure: TypeSpec.Builder.() -> Unit + fun ModuleTemplateBuilder.createInterface(packageName: String, className: String, + configure: TypeSpec.Builder.() -> Unit ) { return createJavaFile(packageName, className, InterfaceType(), configure) } @@ -125,8 +130,8 @@ class JavaSourceBuilder { * @param className The name of the interface. * @param configure Function to configure the [TypeSpec.Builder]. */ - fun createAnnotation(packageName: String, className: String, - configure: TypeSpec.Builder.() -> Unit + fun ModuleTemplateBuilder.createAnnotation(packageName: String, className: String, + configure: TypeSpec.Builder.() -> Unit ) { return createJavaFile(packageName, className, AnnotationType(), configure) } @@ -139,8 +144,8 @@ class JavaSourceBuilder { * @param type The type of the class. * @param configure Function to configure the [TypeSpec.Builder]. */ - fun createJavaFile(packageName: String, className: String, type: SourceType, - configure: TypeSpec.Builder.() -> Unit + fun ModuleTemplateBuilder.createJavaFile(packageName: String, className: String, type: SourceType, + configure: TypeSpec.Builder.() -> Unit ) { val klass = ClassName.get(packageName, className) val builder = type.builder(klass).apply(configure).also { @@ -150,12 +155,62 @@ class JavaSourceBuilder { } val file = JavaFile.builder(packageName, builder.build()) file.skipJavaLangImports(true) - files.add(file.build()) + write(file.build()) } - internal fun ModuleTemplateBuilder.write() { - for (file in files) { - file.writeTo(mainJavaSrc()) - } + /** + * Writes the contents to a new Java file. + * + * @param packageName The package name of the class. + * @param className The name of the class. + * @param source The source code for the file. + */ + fun ModuleTemplateBuilder.writeJavaSrc(packageName: String, className: String, + srcSet: SrcSet = SrcSet.Main, source: String + ) { + executor.save(source, srcFilePath(srcSet, packageName, className, Language.Java)) + } + + /** + * Writes the contents to a new Kotlin file. + * + * @param packageName The package name of the class. + * @param className The name of the class. + * @param source The source code for the file. + */ + fun ModuleTemplateBuilder.writeKtSrc(packageName: String, className: String, + srcSet: SrcSet = SrcSet.Main, source: String + ) { + executor.save(source, srcFilePath(srcSet, packageName, className, Language.Kotlin)) + } + + /** + * Writes the contents to a new Java file. + * + * @param packageName The package name of the class. + * @param className The name of the class. + * @param source A function which returns the source code for the file. + */ + fun ModuleTemplateBuilder.writeJavaSrc(packageName: String, className: String, + srcSet: SrcSet = SrcSet.Main, source: () -> String + ) { + writeJavaSrc(packageName, className, srcSet, source()) + } + + /** + * Writes the contents to a new Kotlin file. + * + * @param packageName The package name of the class. + * @param className The name of the class. + * @param source A function which returns the source code for the file. + */ + fun ModuleTemplateBuilder.writeKtSrc(packageName: String, className: String, + srcSet: SrcSet = SrcSet.Main, source: () -> String + ) { + writeKtSrc(packageName, className, srcSet, source()) + } + + private fun ModuleTemplateBuilder.write(file: JavaFile) { + file.writeTo(mainJavaSrc()) } } diff --git a/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/utils.kt b/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/utils.kt index c771fe941..b4d05bc68 100644 --- a/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/utils.kt +++ b/templates-api/src/main/java/com/itsaky/androidide/templates/base/util/utils.kt @@ -19,9 +19,6 @@ package com.itsaky.androidide.templates.base.util import com.itsaky.androidide.templates.BaseTemplateData import com.itsaky.androidide.templates.ProjectTemplateData -import com.itsaky.androidide.templates.base.AndroidModuleTemplateBuilder -import com.itsaky.androidide.templates.base.ModuleTemplateBuilder -import com.itsaky.androidide.templates.base.ProjectTemplateBuilder import java.io.File /** @@ -39,7 +36,13 @@ internal fun ProjectTemplateData.moduleNameToDir(name: String): File { return File(this.projectDir, moduleNameToDirName(name).replace(':', '/').trim { it == '/' }) } -internal fun moduleNameToDirName(name: String): String { +/** + * Converts a Gradle module name to a directory name. + * + * @param name The module name. + * @return The directory name. + */ +fun moduleNameToDirName(name: String): String { val result = StringBuilder() var prev: Char? = null for (i in name.indices) { diff --git a/templates-impl/build.gradle.kts b/templates-impl/build.gradle.kts index 278552fbb..955c2cb0a 100644 --- a/templates-impl/build.gradle.kts +++ b/templates-impl/build.gradle.kts @@ -15,8 +15,6 @@ * along with AndroidIDE. If not, see . */ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { id("com.android.library") id("org.jetbrains.kotlin.android") @@ -39,6 +37,14 @@ dependencies { implementation(libs.androidx.ktx) implementation(libs.google.auto.service.annotations) - testImplementation(libs.tests.junit) + testImplementation(projects.common) + testImplementation(projects.templatesApi) + testImplementation(projects.lsp.api) + testImplementation(projects.preferences) + testImplementation(projects.shared) + testImplementation(libs.tests.androidx.test.core) testImplementation(libs.tests.google.truth) + testImplementation(libs.tests.junit) + testImplementation(libs.tests.mockk) + testImplementation(libs.tests.robolectric) } \ No newline at end of file diff --git a/templates-impl/src/main/java/com/itsaky/androidide/templates/impl/emptyActivity/emptyActivityTemplate.kt b/templates-impl/src/main/java/com/itsaky/androidide/templates/impl/emptyActivity/emptyActivityTemplate.kt index 1da2504d5..b5e0b769c 100644 --- a/templates-impl/src/main/java/com/itsaky/androidide/templates/impl/emptyActivity/emptyActivityTemplate.kt +++ b/templates-impl/src/main/java/com/itsaky/androidide/templates/impl/emptyActivity/emptyActivityTemplate.kt @@ -17,12 +17,78 @@ package com.itsaky.androidide.templates.impl.emptyActivity +import com.itsaky.androidide.templates.Language import com.itsaky.androidide.templates.ProjectTemplate +import com.itsaky.androidide.templates.base.AndroidModuleTemplateBuilder import com.itsaky.androidide.templates.base.baseProject import com.itsaky.androidide.templates.base.modules.android.defaultAppModule fun emptyActivityProject(): ProjectTemplate = baseProject { defaultAppModule { - + recipe = { + writeEmptyActivityModule() + } } -} \ No newline at end of file +} + +internal fun AndroidModuleTemplateBuilder.writeEmptyActivityModule() { + sources { + if (data.language == Language.Kotlin) { + writeKtSrc(data.packageName, "MainActivity", + source = this@writeEmptyActivityModule::emptyActivityKtSrc) + } else { + writeJavaSrc(packageName = data.packageName, className = "MainActivity", + source = this@writeEmptyActivityModule::emptyActivityJavaSrc) + } + } +} + +private fun AndroidModuleTemplateBuilder.emptyActivityKtSrc(): String { + return """ +package ${data.packageName} + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import ${data.packageName}.databinding.ActivityMainBinding + +public class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Inflate and get instance of binding + binding = ActivityMainBinding.inflate(layoutInflater) + + // set content view to binding's root + setContentView(binding.root) + } +} +""" +} + +private fun AndroidModuleTemplateBuilder.emptyActivityJavaSrc(): String { + return """ +package ${data.packageName}; + +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; +import ${data.packageName}.databinding.ActivityMainBinding; + +public class MainActivity extends AppCompatActivity { + private ActivityMainBinding binding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Inflate and get instance of binding + binding = ActivityMainBinding.inflate(getLayoutInflater()); + + // set content view to binding's root + setContentView(binding.getRoot()); + } +} +""" +} diff --git a/templates-api/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt b/templates-impl/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt similarity index 83% rename from templates-api/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt rename to templates-impl/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt index 119ae6a78..d74bd3611 100644 --- a/templates-api/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt +++ b/templates-impl/src/test/java/com/itsaky/androidide/templates/TemplateBuilderTest.kt @@ -22,6 +22,7 @@ import com.itsaky.androidide.templates.base.modules.android.ManifestActivity import com.itsaky.androidide.templates.base.modules.android.defaultAppModule import com.itsaky.androidide.templates.base.modules.createConstructor import com.itsaky.androidide.templates.base.modules.createMethod +import com.itsaky.androidide.templates.impl.emptyActivity.writeEmptyActivityModule import com.itsaky.androidide.xml.permissions.Permission import com.squareup.javapoet.ArrayTypeName import com.squareup.javapoet.ParameterSpec @@ -32,6 +33,7 @@ import jdkx.lang.model.element.Modifier.STATIC import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner +import java.lang.String /** * Test template builder. @@ -99,7 +101,7 @@ class TemplateBuilderTest { ManifestActivity(name = ".MainActivity", isExported = true, isLauncher = true)) } - java { + sources { createClass("com.itsaky", "TestClass") { createConstructor { addModifiers(PRIVATE) @@ -109,8 +111,7 @@ class TemplateBuilderTest { addModifiers(PUBLIC, STATIC) returns(TypeName.VOID) addParameter( - ParameterSpec.builder(ArrayTypeName.get(java.lang.String::class.java), "args") - .build()) + ParameterSpec.builder(ArrayTypeName.get(String::class.java), "args").build()) addStatement("System.out.println(\"Hello world!\")") } } @@ -123,4 +124,23 @@ class TemplateBuilderTest { template.setupRootProjectParams() template.executeRecipe() } + + @Test + fun `test empty activity template`() { + val template = testTemplate { + defaultAppModule { + recipe = { + writeEmptyActivityModule() + } + } + } + + // Write the Java version of the project + template.setupRootProjectParams("EmptyActivityProjectJava", language = Language.Java) + template.executeRecipe() + + // Write the Kotlin version of the project + template.setupRootProjectParams("EmptyActivityProjectKt", language = Language.Kotlin) + template.executeRecipe() + } } \ No newline at end of file diff --git a/templates-api/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt b/templates-impl/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt similarity index 88% rename from templates-api/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt rename to templates-impl/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt index a93d2af87..62c14581d 100644 --- a/templates-api/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt +++ b/templates-impl/src/test/java/com/itsaky/androidide/templates/TestRecipeExecutor.kt @@ -17,6 +17,7 @@ package com.itsaky.androidide.templates +import com.itsaky.androidide.utils.FileProvider import java.io.File import java.io.InputStream @@ -28,7 +29,7 @@ import java.io.InputStream class TestRecipeExecutor : RecipeExecutor { private val assets by lazy { - File("./src/main/assets") + File(FileProvider.projectRoot().toFile(), "templates-api/src/main/assets") } override fun copy(source: File, dest: File) { @@ -51,6 +52,6 @@ class TestRecipeExecutor : RecipeExecutor { } override fun copyAssetsRecursively(path: String, destDir: File) { - File(this.assets, path).copyRecursively(destDir) + File(this.assets, path).copyRecursively(destDir, true) } } \ No newline at end of file diff --git a/templates-api/src/test/java/com/itsaky/androidide/templates/UtilTest.kt b/templates-impl/src/test/java/com/itsaky/androidide/templates/UtilTest.kt similarity index 100% rename from templates-api/src/test/java/com/itsaky/androidide/templates/UtilTest.kt rename to templates-impl/src/test/java/com/itsaky/androidide/templates/UtilTest.kt diff --git a/templates-api/src/test/java/com/itsaky/androidide/templates/utils.kt b/templates-impl/src/test/java/com/itsaky/androidide/templates/utils.kt similarity index 85% rename from templates-api/src/test/java/com/itsaky/androidide/templates/utils.kt rename to templates-impl/src/test/java/com/itsaky/androidide/templates/utils.kt index a8e7da17c..f9da707d4 100644 --- a/templates-api/src/test/java/com/itsaky/androidide/templates/utils.kt +++ b/templates-impl/src/test/java/com/itsaky/androidide/templates/utils.kt @@ -21,8 +21,8 @@ import androidx.test.core.app.ApplicationProvider import com.google.common.truth.Truth.assertThat import com.itsaky.androidide.managers.PreferenceManager import com.itsaky.androidide.preferences.internal.prefManager -import com.itsaky.androidide.templates.base.baseProject import com.itsaky.androidide.templates.base.ProjectTemplateConfigurator +import com.itsaky.androidide.templates.base.baseProject import com.itsaky.androidide.utils.Environment import com.itsaky.androidide.utils.FileProvider import io.mockk.every @@ -62,16 +62,19 @@ fun testTemplate(block: ProjectTemplateConfigurator): Template { } } -fun Template.setupRootProjectParams() { +fun Template.setupRootProjectParams(name: String = "TestTemplate", + packageName: String = "com.itsaky.androidide.template", + language: Language = Language.Kotlin, minSdk: Sdk = Sdk.Lollipop +) { val iterator = parameters.iterator() // name var param = iterator.next() - (param as StringParameter).value = "TestTemplate" + (param as StringParameter).value = name // package param = iterator.next() - (param as StringParameter).value = "com.itsaky.androidide.template" + (param as StringParameter).value = packageName // save location param = iterator.next() @@ -79,11 +82,11 @@ fun Template.setupRootProjectParams() { // language param = iterator.next() - (param as EnumParameter).value = Language.Kotlin + (param as EnumParameter).value = language // Min SDK param = iterator.next() - (param as EnumParameter).value = Sdk.Lollipop + (param as EnumParameter).value = minSdk } fun Template.executeRecipe() {