Skip to content
This repository has been archived by the owner on Dec 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #78 from NikitaKozlov/add-method-calls-to-activity
Browse files Browse the repository at this point in the history
Add method calls to activity
  • Loading branch information
borisf authored Feb 9, 2018
2 parents da13a8b + 1580d34 commit 86694a6
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,63 +16,54 @@ limitations under the License.

package com.google.androidstudiopoet.generators.android_modules

import com.google.androidstudiopoet.GenerationResult
import com.google.androidstudiopoet.models.AndroidModuleBlueprint
import com.google.androidstudiopoet.models.ActivityBlueprint
import com.google.androidstudiopoet.models.ClassBlueprint
import com.google.androidstudiopoet.writers.FileWriter
import java.io.File
import com.squareup.javapoet.*
import javax.lang.model.element.Modifier


class ActivityGenerator(var fileWriter: FileWriter) {

/**
* generates activity classes by blueprint, list of layouts and methods to call.
*/
fun generate(blueprint: AndroidModuleBlueprint) {
fun generate(blueprint: ActivityBlueprint) {

val classBlueprint = blueprint.classBlueprint
val onCreateMethodStatements = getMethodStatementFromClassToCall(classBlueprint)?.let { listOf(it) } ?: listOf()

val onCreateMethod = getOnCreateMethod(blueprint.layout, onCreateMethodStatements)

val activityClass = getClazzSpec(blueprint.className)
.addMethod(onCreateMethod)
.build()

// generate activities
var index = 0
val javaFile = JavaFile.builder(blueprint.packageName, activityClass).build()

File(blueprint.packagePath).mkdirs()
println("${blueprint.where}/${blueprint.className}.java")
fileWriter.writeToFile(javaFile.toString(), "${blueprint.where}/${blueprint.className}.java")

while (index < blueprint.numOfActivities) {
generateClass(blueprint.activityNames[index], blueprint.layoutNames[index], blueprint.packagePath, blueprint.packageName)
index++
}
}

private fun generateClass(className: String, layout: String, where: String, packageName: String) {

// TODO add methods
// TODO move to java poet
val classText =
"package $packageName;\n" +
"import android.app.Activity;\n" +
"import android.os.Bundle;\n" +
"import $packageName.R;\n" +
"\n" +
"\n" +
"public class " + className + " extends Activity {\n" +
" public $className() {\n" +
" }\n" +
"\n" +
" /**\n" +
" * Called with the activity is first created.\n" +
" */\n" +
" @Override\n" +
" public void onCreate(Bundle savedInstanceState) {\n" +
" super.onCreate(savedInstanceState);\n" +
"\n" +
" // Set the layout for this activity. You can find it\n" +
" // in res/layout/hello_activity.xml\n" +
" setContentView(R.layout." + layout + ");\n" +
" }\n" +
"}\n"

println("$where/$className.java")

fileWriter.writeToFile(classText, "$where/$className.java")
private fun getMethodStatementFromClassToCall(classBlueprint: ClassBlueprint) =
classBlueprint.getMethodToCallFromOutside()?.let { "new ${it.className}().${it.methodName}()" }

private fun getClazzSpec(activityClassName: String) =
TypeSpec.classBuilder(activityClassName)
.superclass(TypeVariableName.get("android.app.Activity"))
.addModifiers(Modifier.PUBLIC)

private fun getOnCreateMethod(layout: String, statements: List<String>): MethodSpec {

val builder = MethodSpec.methodBuilder("onCreate")
.addAnnotation(Override::class.java)
.addModifiers(Modifier.PUBLIC)
.returns(Void.TYPE)
.addParameter(TypeVariableName.get("android.os.Bundle"), "savedInstanceState")
.addStatement("super.onCreate(savedInstanceState)")
.addStatement("setContentView(R.layout.$layout)")

statements.forEach { builder.addStatement(it) }
return builder.build();
}

data class ActivityGenerationResult(val activityNames: List<String>) : GenerationResult
}

Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class AndroidModuleGenerator(private val resourcesGenerator: ResourcesGenerator,
buildGradleGenerator.generate(blueprint)
blueprint.resourcesBlueprint?.let { resourcesGenerator.generate(it) }
packagesGenerator.writePackages(blueprint.packagesBlueprint)
activityGenerator.generate(blueprint)
blueprint.activityBlueprints.forEach({ activityGenerator.generate(it) })
manifestGenerator.generate(blueprint)
}

Expand All @@ -52,5 +52,6 @@ class AndroidModuleGenerator(private val resourcesGenerator: ResourcesGenerator,
fileWriter.mkdir(blueprint.mainPath)
fileWriter.mkdir(blueprint.codePath)
fileWriter.mkdir(blueprint.resDirPath)
fileWriter.mkdir(blueprint.packagePath)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.google.androidstudiopoet.models

data class ActivityBlueprint(val className: String, val layout: String, val where: String, val packageName: String,
val classBlueprint: ClassBlueprint)
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ import com.google.androidstudiopoet.utils.joinPath
import com.google.androidstudiopoet.utils.joinPaths

class AndroidModuleBlueprint(name: String,
val numOfActivities: Int,
private val resourcesConfig: ResourcesConfig?,
projectRoot: String,
val hasLaunchActivity: Boolean,
useKotlin: Boolean,
dependencies: List<ModuleDependency>,
productFlavorConfigs: List<FlavorConfig>?,
buildTypeConfigs: List<BuildTypeConfig>?,
javaPackageCount: Int, javaClassCount: Int, javaMethodsPerClass: Int,
kotlinPackageCount: Int, kotlinClassCount: Int, kotlinMethodsPerClass: Int,
extraLines: List<String>?,
generateTests : Boolean
val numOfActivities: Int,
private val resourcesConfig: ResourcesConfig?,
projectRoot: String,
val hasLaunchActivity: Boolean,
useKotlin: Boolean,
dependencies: List<ModuleDependency>,
productFlavorConfigs: List<FlavorConfig>?,
buildTypeConfigs: List<BuildTypeConfig>?,
javaPackageCount: Int, javaClassCount: Int, javaMethodsPerClass: Int,
kotlinPackageCount: Int, kotlinClassCount: Int, kotlinMethodsPerClass: Int,
extraLines: List<String>?,
generateTests: Boolean
) : ModuleBlueprint(name, projectRoot, useKotlin, dependencies, javaPackageCount, javaClassCount,
javaMethodsPerClass, kotlinPackageCount, kotlinClassCount, kotlinMethodsPerClass, extraLines, generateTests) {

Expand All @@ -58,10 +58,10 @@ class AndroidModuleBlueprint(name: String,
}
}

val layoutNames by lazy {
private val layoutNames by lazy {
resourcesBlueprint?.layoutNames ?: listOf()
}
val activityNames = 0.until(numOfActivities).map { "Activity$it" }
val activityNames = (0 until numOfActivities).map { "Activity$it" }

val resourcesToReferFromOutside by lazy {
resourcesBlueprint?.resourcesToReferFromOutside ?: ResourcesToRefer(listOf(), listOf(), listOf())
Expand All @@ -70,5 +70,15 @@ class AndroidModuleBlueprint(name: String,
val productFlavors = productFlavorConfigs?.map { Flavor(it.name, it.dimension) }?.toSet()
val flavorDimensions = productFlavors?.mapNotNull { it.dimension }?.toSet()

val buildTypes = buildTypeConfigs?.map {BuildType(it.name, it.body)}?.toSet()
val buildTypes = buildTypeConfigs?.map { BuildType(it.name, it.body) }?.toSet()
val activityBlueprints by lazy {
(0 until numOfActivities).map { ActivityBlueprint(activityNames[it], layoutNames[it], packagePath, packageName,
classToReferFromActivity) }
}

private val classToReferFromActivity: ClassBlueprint by lazy {
(packagesBlueprint.javaPackageBlueprints.asSequence() + packagesBlueprint.kotlinPackageBlueprints.asSequence())
.flatMap { it.classBlueprints.asSequence() }
.first()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,30 @@ data class ResourcesBlueprint(private val moduleName: String,
private val imageCount: Int,
private val layoutCount: Int,
private val resourcesToReferWithin: ResourcesToRefer) : Blueprint {
val stringNames = (0..stringCount).map { "${moduleName}string$it" }
val stringNames = (0 until stringCount).map { "${moduleName}string$it" }
val imageNames = (0 until imageCount).map { "${moduleName.toLowerCase()}image$it" }

val layoutNames = (0 until layoutCount).map { "${moduleName.toLowerCase()}activity_main$it" }

val layoutsDir = resDirPath.joinPath("layout")

private val stringsPerLayout = (stringNames + resourcesToReferWithin.strings).splitPerLayout(layoutCount)
private val imagesPerLayout = (imageNames + resourcesToReferWithin.images).splitPerLayout(layoutCount)
private val stringsPerLayout by lazy {
(stringNames + resourcesToReferWithin.strings).splitPerLayout(layoutCount)
}
private val imagesPerLayout by lazy {
(imageNames + resourcesToReferWithin.images).splitPerLayout(layoutCount)
}

val layoutBlueprints = layoutNames.mapIndexed { index, layoutName ->
LayoutBlueprint(layoutsDir.joinPath(layoutName) + ".xml",
stringsPerLayout.getOrElse(index, { listOf() }),
imagesPerLayout.getOrElse(index, { listOf() }),
if (index == 0) resourcesToReferWithin.layouts else listOf()) }
if (index == 0) resourcesToReferWithin.layouts else listOf())
}

var resourcesToReferFromOutside = ResourcesToRefer(listOf(stringNames.last()), listOf(imageNames.last()), listOf(layoutNames.last()))
val resourcesToReferFromOutside by lazy {
ResourcesToRefer(listOf(stringNames.last()), listOf(imageNames.last()), listOf(layoutNames.last()))
}
}

fun List<String>.splitPerLayout(limit: Int) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import com.google.androidstudiopoet.input.BuildTypeConfig
import com.google.androidstudiopoet.input.FlavorConfig
import com.google.androidstudiopoet.input.ResourcesConfig
import com.google.androidstudiopoet.testutils.assertEquals
import com.google.androidstudiopoet.testutils.assertOn
import com.google.androidstudiopoet.testutils.mock
import com.nhaarman.mockito_kotlin.whenever
import org.junit.Test

class AndroidModuleBlueprintTest {
private val resourcesConfig0: ResourcesConfig = mock()
private val dependency: ModuleDependency = mock()

@Test
fun `blueprint create proper activity names`() {
Expand Down Expand Up @@ -39,6 +40,38 @@ class AndroidModuleBlueprintTest {
))
}

@Test
fun `blueprint creates activity blueprint with java class when java code exists`() {
whenever(resourcesConfig0.layoutCount).thenReturn(1)

val androidModuleBlueprint = getAndroidModuleBlueprint()

assertOn(androidModuleBlueprint) {
activityBlueprints.assertEquals(listOf(ActivityBlueprint(
"Activity0",
androidModuleBlueprint.resourcesBlueprint!!.layoutNames[0],
androidModuleBlueprint.packagePath,
androidModuleBlueprint.packageName,
androidModuleBlueprint.packagesBlueprint.javaPackageBlueprints[0].classBlueprints[0])))
}
}

@Test
fun `blueprint creates activity blueprint with koltin class when java code doesn't exist`() {
whenever(resourcesConfig0.layoutCount).thenReturn(1)

val androidModuleBlueprint = getAndroidModuleBlueprint(
javaClassCount = 0,
javaMethodsPerClass = 0,
javaPackageCount = 0
)

assertOn(androidModuleBlueprint) {
activityBlueprints[0].classBlueprint.assertEquals(
androidModuleBlueprint.packagesBlueprint.kotlinPackageBlueprints[0].classBlueprints[0])
}
}


private fun getAndroidModuleBlueprint(
name: String = "androidAppModule1",
Expand All @@ -47,7 +80,7 @@ class AndroidModuleBlueprintTest {
projectRoot: String = "root",
hasLaunchActivity: Boolean = true,
useKotlin: Boolean = false,
dependencies: List<ModuleDependency> = listOf(dependency),
dependencies: List<ModuleDependency> = listOf(),
productFlavorConfigs: List<FlavorConfig>? = null,
buildTypeConfigs: List<BuildTypeConfig>? = null,
javaPackageCount: Int = 1,
Expand Down

0 comments on commit 86694a6

Please sign in to comment.