Skip to content

Commit 260253c

Browse files
committed
sfg-5 Move the general logic to BaseVisitor, sfg-4 Replace Fragment.bind -> Fragment.initArguments
1 parent dfb6dd8 commit 260253c

File tree

5 files changed

+255
-182
lines changed

5 files changed

+255
-182
lines changed

app/src/main/java/com/example/screenfactorygeneratorsample/FirstFragment.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ import android.view.ViewGroup
77
import androidx.fragment.app.Fragment
88
import androidx.navigation.fragment.findNavController
99
import com.example.screenfactorygeneratorsample.databinding.FragmentFirstBinding
10+
import com.udfsoft.screenfactorygenerator.annotation.JParam
11+
import com.udfsoft.screenfactorygenerator.annotation.JScreen
1012

1113
/**
1214
* A simple [Fragment] subclass as the default destination in the navigation.
1315
*/
16+
@JScreen(generateScreenMethod = false)
1417
class FirstFragment : Fragment() {
1518

1619
private var _binding: FragmentFirstBinding? = null
@@ -19,14 +22,20 @@ class FirstFragment : Fragment() {
1922
// onDestroyView.
2023
private val binding get() = _binding!!
2124

25+
@JParam
26+
var test1: String = ""
27+
28+
override fun onCreate(savedInstanceState: Bundle?) {
29+
super.onCreate(savedInstanceState)
30+
}
31+
2232
override fun onCreateView(
2333
inflater: LayoutInflater, container: ViewGroup?,
2434
savedInstanceState: Bundle?
2535
): View? {
2636

2737
_binding = FragmentFirstBinding.inflate(inflater, container, false)
2838
return binding.root
29-
3039
}
3140

3241
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

screen-generator-processor/src/main/java/com/udfsoft/screenfactorygenerator/processor/JScreenProcessor.kt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import com.udfsoft.screenfactorygenerator.processor.visitor.ActivityVisitor
2626
import com.udfsoft.screenfactorygenerator.processor.visitor.FragmentVisitor
2727
import com.udfsoft.screenfactorygenerator.utils.IoUtils.plusAssign
2828
import com.udfsoft.screenfactorygenerator.utils.Utils.isChildForClass
29-
import com.udfsoft.screenfactorygenerator.utils.Utils.replaceFirst
3029

3130
class JScreenProcessor(
3231
private val codeGenerator: CodeGenerator,
@@ -80,9 +79,23 @@ class JScreenProcessor(
8079
sourceFile += "package $packageName\n\n"
8180

8281
if (it.isChildForClass("Fragment")) {
83-
it.accept(FragmentVisitor(sourceFile, className, logger), Unit)
82+
it.accept(
83+
FragmentVisitor(
84+
sourceFile,
85+
className,
86+
logger,
87+
screenManagerClassStringBuilder
88+
), Unit
89+
)
8490
} else if (it.isChildForClass("Activity")) {
85-
it.accept(ActivityVisitor(sourceFile, className, logger, screenManagerClassStringBuilder), Unit)
91+
it.accept(
92+
ActivityVisitor(
93+
sourceFile,
94+
className,
95+
logger,
96+
screenManagerClassStringBuilder
97+
), Unit
98+
)
8699
}
87100
sourceFile.close()
88101
}

screen-generator-processor/src/main/java/com/udfsoft/screenfactorygenerator/processor/visitor/ActivityVisitor.kt

Lines changed: 61 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -18,130 +18,87 @@
1818
package com.udfsoft.screenfactorygenerator.processor.visitor
1919

2020
import com.google.devtools.ksp.processing.KSPLogger
21-
import com.google.devtools.ksp.symbol.ClassKind
22-
import com.google.devtools.ksp.symbol.KSAnnotation
23-
import com.google.devtools.ksp.symbol.KSClassDeclaration
24-
import com.google.devtools.ksp.symbol.KSVisitorVoid
25-
import com.udfsoft.screenfactorygenerator.annotation.JParam
26-
import com.udfsoft.screenfactorygenerator.annotation.JScreen
21+
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
22+
import com.google.devtools.ksp.symbol.KSValueArgument
2723
import com.udfsoft.screenfactorygenerator.processor.mapper.KSPropertyDeclarationToIntentPutExtraString
2824
import com.udfsoft.screenfactorygenerator.processor.mapper.KsPropertyDeclarationToGetExtraString
29-
import com.udfsoft.screenfactorygenerator.utils.IoUtils.plusAssign
30-
import com.udfsoft.screenfactorygenerator.utils.Utils.findAnnotation
31-
import com.udfsoft.screenfactorygenerator.utils.Utils.findArgument
32-
import com.udfsoft.screenfactorygenerator.utils.Utils.getDeclaredPropertiesWithAnnotation
33-
import com.udfsoft.screenfactorygenerator.utils.Utils.isChildForClass
34-
import com.udfsoft.screenfactorygenerator.utils.Utils.replaceFirst
3525
import java.io.OutputStream
3626

3727
class ActivityVisitor(
38-
private val file: OutputStream,
39-
private val className: String,
28+
file: OutputStream,
29+
className: String,
4030
private val logger: KSPLogger,
41-
private val screenManagerClassStringBuilder: StringBuilder
42-
) : KSVisitorVoid() {
31+
screenManagerClassStringBuilder: StringBuilder
32+
) : BaseVisitor(file, className, logger, screenManagerClassStringBuilder) {
4333

44-
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
45-
if (classDeclaration.classKind != ClassKind.CLASS) {
46-
logger.error("Only class can be annotated with @JScreen", classDeclaration)
47-
return
48-
}
49-
50-
val isActivity = classDeclaration.isChildForClass("Activity")
51-
52-
if (!isActivity) {
53-
logger.error("Class must be inherited from Activity", classDeclaration)
54-
return
55-
}
34+
override fun getParentClassString() = ACTIVITY_CLASS_NAME
5635

57-
val annotation: KSAnnotation = classDeclaration.findAnnotation(JScreen::class.simpleName!!)
58-
59-
val generateScreenMethodArgument = annotation.arguments.findArgument("generateScreenMethod")
60-
61-
val params =
62-
classDeclaration.getDeclaredPropertiesWithAnnotation(JParam::class.simpleName!!)
63-
64-
if (generateScreenMethodArgument.value == true) {
65-
file += "import com.github.terrakok.cicerone.androidx.ActivityScreen\n"
66-
}
36+
override fun getImportForGenericClass(generateScreenMethodArgument: KSValueArgument) =
37+
buildString {
38+
if (generateScreenMethodArgument.value == true) {
39+
appendLine("import com.github.terrakok.cicerone.androidx.ActivityScreen")
40+
}
6741

68-
file += "import android.content.Context\n"
69-
file += "import android.content.Intent\n"
70-
file += "import androidx.core.os.bundleOf\n"
71-
file += "import androidx.fragment.app.Fragment\n"
72-
file += "import com.udfsoft.screenfactorygenerator.BaseScreen\n\n"
73-
74-
file += "object ${className}Screen : BaseScreen {\n\n"
75-
76-
file += if (params.toList().isEmpty()) {
77-
" fun newIntent(context: Context) = Intent(context, ${className}::class.java)\n\n"
78-
} else {
79-
val paramsForSetArguments =
80-
params.map(KSPropertyDeclarationToIntentPutExtraString()::transform)
81-
.joinToString("\n ")
82-
83-
val paramsInString = params.map {
84-
"$it: ${it.type}"
85-
}.joinToString()
86-
87-
" fun newIntent(context: Context, $paramsInString): Intent { \n" +
88-
" val intent = Intent(context, ${className}::class.java)\n" +
89-
" $paramsForSetArguments\n" +
90-
" return intent\n" +
91-
" }\n\n"
42+
appendLine("import android.content.Context")
43+
appendLine("import android.content.Intent")
44+
appendLine("import androidx.core.os.bundleOf")
45+
appendLine("import androidx.fragment.app.Fragment")
46+
appendLine("import com.udfsoft.screenfactorygenerator.BaseScreen\n")
9247
}
9348

94-
file += " fun ${className}.initArguments() {\n"
95-
96-
val paramsForGetArguments = params.map(KsPropertyDeclarationToGetExtraString()::transform)
97-
.joinToString("\n")
98-
99-
file += "$paramsForGetArguments\n"
100-
file += " }\n"
101-
102-
if (generateScreenMethodArgument.value == true) {
103-
file += "\n"
104-
file += if (params.toList().isEmpty()) {
105-
" fun get${className}Screen() = ActivityScreen { newIntent(it) }\n"
49+
override fun getClassBody(
50+
params: Sequence<KSPropertyDeclaration>,
51+
generateScreenMethodArgument: KSValueArgument,
52+
className: String
53+
): String = buildString {
54+
appendLine(
55+
if (params.toList().isEmpty()) {
56+
" fun newIntent(context: Context) = Intent(context, ${className}::class.java)\n"
10657
} else {
107-
108-
val paramsWithTypeInString = params.map {
109-
"$it: ${it.type}"
110-
}.joinToString()
58+
val paramsForSetArguments =
59+
params.map(KSPropertyDeclarationToIntentPutExtraString()::transform)
60+
.joinToString("\n ")
11161

11262
val paramsInString = params.map {
113-
"$it"
63+
"$it: ${it.type}"
11464
}.joinToString()
11565

116-
" fun get${className}Screen($paramsWithTypeInString) = ActivityScreen {\n" +
117-
" newIntent(it, $paramsInString)\n" +
118-
" }\n"
66+
" fun newIntent(context: Context, $paramsInString): Intent { \n" +
67+
" val intent = Intent(context, ${className}::class.java)\n" +
68+
" $paramsForSetArguments\n" +
69+
" return intent\n" +
70+
" }\n"
11971
}
120-
}
72+
)
12173

122-
file += "}\n"
74+
appendLine(" fun ${className}.initArguments() {")
12375

124-
val packageName = classDeclaration.containingFile!!.packageName.asString()
125-
val importIndex = screenManagerClassStringBuilder.indexOf("import")
126-
screenManagerClassStringBuilder.insert(
127-
importIndex,
128-
"import ${packageName}.${className}Screen.initArguments\n"
129-
)
130-
screenManagerClassStringBuilder.insert(importIndex, "import ${packageName}.$className\n")
76+
val paramsForGetArguments = params.map(KsPropertyDeclarationToGetExtraString()::transform)
77+
.joinToString("\n")
13178

132-
if (screenManagerClassStringBuilder.contains("// initArguments(Activities)")) {
133-
val body = buildString {
134-
appendLine("\rwhen (activity) {")
135-
append(" is $className -> activity.initArguments()")
136-
append(" }")
137-
}
138-
screenManagerClassStringBuilder.replaceFirst("// initArguments(Activities)", body)
139-
} else {
140-
val body = buildString {
141-
appendLine(" when (activity) {")
142-
append(" is $className -> activity.initArguments()")
143-
}
144-
screenManagerClassStringBuilder.replaceFirst("when (activity) {", body)
79+
appendLine(paramsForGetArguments)
80+
appendLine(" }")
81+
82+
if (generateScreenMethodArgument.value == true) {
83+
appendLine()
84+
appendLine(
85+
if (params.toList().isEmpty()) {
86+
" fun get${className}Screen() = ActivityScreen { newIntent(it) }"
87+
} else {
88+
89+
val paramsWithTypeInString = params.map {
90+
"$it: ${it.type}"
91+
}.joinToString()
92+
93+
val paramsInString = params.map {
94+
"$it"
95+
}.joinToString()
96+
97+
" fun get${className}Screen($paramsWithTypeInString) = ActivityScreen {\n" +
98+
" newIntent(it, $paramsInString)\n" +
99+
" }"
100+
}
101+
)
145102
}
146103
}
147104
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright 2022 javavirys
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.udfsoft.screenfactorygenerator.processor.visitor
19+
20+
import com.google.devtools.ksp.processing.KSPLogger
21+
import com.google.devtools.ksp.symbol.*
22+
import com.udfsoft.screenfactorygenerator.annotation.JParam
23+
import com.udfsoft.screenfactorygenerator.annotation.JScreen
24+
import com.udfsoft.screenfactorygenerator.utils.IoUtils.plusAssign
25+
import com.udfsoft.screenfactorygenerator.utils.Utils.findAnnotation
26+
import com.udfsoft.screenfactorygenerator.utils.Utils.findArgument
27+
import com.udfsoft.screenfactorygenerator.utils.Utils.getDeclaredPropertiesWithAnnotation
28+
import com.udfsoft.screenfactorygenerator.utils.Utils.isChildForClass
29+
import com.udfsoft.screenfactorygenerator.utils.Utils.replaceFirst
30+
import java.io.OutputStream
31+
32+
abstract class BaseVisitor(
33+
private val file: OutputStream,
34+
private val className: String,
35+
private val logger: KSPLogger,
36+
private val screenManagerClassStringBuilder: StringBuilder
37+
) : KSVisitorVoid() {
38+
39+
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
40+
if (classDeclaration.classKind != ClassKind.CLASS) {
41+
logger.error("Only class can be annotated with @JScreen", classDeclaration)
42+
return
43+
}
44+
45+
val isChild = classDeclaration.isChildForClass(getParentClassString())
46+
47+
if (!isChild) {
48+
logger.error("Class must be inherited from ${getParentClassString()}", classDeclaration)
49+
return
50+
}
51+
52+
val annotation: KSAnnotation = classDeclaration.findAnnotation(JScreen::class.simpleName!!)
53+
54+
val generateScreenMethodArgument = annotation.arguments.findArgument("generateScreenMethod")
55+
56+
val params =
57+
classDeclaration.getDeclaredPropertiesWithAnnotation(JParam::class.simpleName!!)
58+
59+
file += getImportForGenericClass(generateScreenMethodArgument)
60+
61+
file += "object ${className}Screen : BaseScreen {\n\n"
62+
file += getClassBody(params, generateScreenMethodArgument, className)
63+
file += "}\n"
64+
65+
val packageName = classDeclaration.containingFile!!.packageName.asString()
66+
val importIndex = screenManagerClassStringBuilder.indexOf("import")
67+
screenManagerClassStringBuilder.insert(
68+
importIndex,
69+
"import ${packageName}.${className}Screen.initArguments\n"
70+
)
71+
screenManagerClassStringBuilder.insert(importIndex, "import ${packageName}.$className\n")
72+
73+
if (getParentClassString() == ACTIVITY_CLASS_NAME) {
74+
createScreenManagerBody("// initArguments(Activities)", name = "activity")
75+
} else if (getParentClassString() == FRAGMENT_CLASS_NAME) {
76+
createScreenManagerBody("// initArguments(Fragments)", name = "fragment")
77+
}
78+
}
79+
80+
private fun createScreenManagerBody(replaceString: String, name: String) {
81+
if (screenManagerClassStringBuilder.contains(replaceString)) {
82+
val body = buildString {
83+
appendLine("when ($name) {")
84+
appendLine(" is $className -> $name.initArguments()")
85+
append(" }")
86+
}
87+
screenManagerClassStringBuilder.replaceFirst(replaceString, body)
88+
} else {
89+
val body = buildString {
90+
appendLine("when ($name) {")
91+
append(" is $className -> $name.initArguments()")
92+
}
93+
screenManagerClassStringBuilder.replaceFirst("when ($name) {", body)
94+
}
95+
}
96+
97+
abstract fun getParentClassString(): String
98+
99+
abstract fun getImportForGenericClass(generateScreenMethodArgument: KSValueArgument): String
100+
101+
abstract fun getClassBody(
102+
params: Sequence<KSPropertyDeclaration>,
103+
generateScreenMethodArgument: KSValueArgument,
104+
className: String
105+
): String
106+
107+
companion object {
108+
const val FRAGMENT_CLASS_NAME = "Fragment"
109+
const val ACTIVITY_CLASS_NAME = "Activity"
110+
}
111+
}

0 commit comments

Comments
 (0)