Skip to content

Commit

Permalink
Improve code generation and add support for new activity result frame…
Browse files Browse the repository at this point in the history
…work (#6)
  • Loading branch information
cedrickcooke committed Mar 23, 2020
1 parent f42318d commit adf5c24
Show file tree
Hide file tree
Showing 30 changed files with 668 additions and 219 deletions.
49 changes: 31 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,23 @@ First, add it to gradle.
// In your root build.gradle
allprojects {
repositories {
// ...
maven { url 'https://jitpack.io' }
}
}
// In your application build.gradle
android {
defaultConfig {
applicationId "your.application.id"
javaCompileOptions {
annotationProcessorOptions {
arguments = [ "exercise.packageName": "your.application.id" ]
}
}
}
}
dependencies {
// ...
implementation "com.github.juullabs-oss.android-exercise:annotations:$version"
kapt "com.github.juullabs-oss.android-exercise:compile:$version"
}
Expand All @@ -42,35 +51,39 @@ class FromActivity : AppCompatActivity() {
// ...

fun navigate() {
startActivity(intentForYourActivity(someNumber = 25))
startActivity(YourActivityIntent(someNumber = 25))
}
}
```
## Under the Hood

Sometimes, the easiest way to learn is to know what's happening behind the scenes.
Exercise does not generate absurd amounts of complicated code.
Instead, it's the kind of boilerplate you might write by hand.
Exercise works just like vanilla Android, using `Intent` passing and `Bundle`s.

```kotlin
class YourActivityIntent(
someNumber: Int
) : Intent() {
init {
component = ComponentName(
"com.juullabs.exercise",
"com.juullabs.exercise.activities.YourActivity"
)
replaceExtras(bundleOf(
"com.juullabs.exercise.someNumber" to someNumber
))
}
}

internal class YourActivityExtras(
private val instance: YourActivity
private val instance: YourActivity
) {
val someNumber: Int
get() = with (instance) {
intent?.extras?.get("$packageName.someNumber") as kotlin.Int
}
val someNumber: Int
get() = instance.intent?.extras?.get("com.juullabs.exercise.someNumber") as Int
}

internal val YourActivity.extras: YourActivityExtras
get() = YourActivityExtras(this)

fun Context.intentForYourActivity(someNumber: Int): Intent {
val intent = Intent(this, YourActivity::class.java)
return intent.apply {
replaceExtras(bundleOf("$packageName.someNumber" to someNumber))
}
}
get() = YourActivityExtras(this)
```

# License
Expand Down
1 change: 0 additions & 1 deletion annotations/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ apply plugin: 'kotlin'
apply plugin: 'maven-publish'

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package com.juullabs.exercise.annotations
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Exercise(vararg val extras: ExerciseParameter)
annotation class Exercise(vararg val params: ExerciseParameter)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.juullabs.exercise.annotations

@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class ResultContract(vararg val kinds: ResultKind)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.juullabs.exercise.annotations

@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class ResultKind(val name: String, vararg val params: ExerciseParameter)
15 changes: 11 additions & 4 deletions application/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ android {

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

javaCompileOptions {
annotationProcessorOptions {
arguments = [
"exercise.packageName": "com.juullabs.exercise"
]
}
}
}

buildTypes {
Expand All @@ -35,13 +42,13 @@ android {
}

dependencies {

implementation fileTree(dir: "libs", include: ["*.jar"])
implementation project(":annotations")
kapt project(":compile")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.core:core-ktx:1.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.activity:activity-ktx:1.2.0-alpha02'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha02'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
Expand Down
2 changes: 2 additions & 0 deletions application/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

<activity android:name=".FragmentContainerActivity" />

<activity android:name=".activities.CalculatorChildActivity" />
<activity android:name=".activities.CalculatorParentActivity" />
<activity android:name=".activities.ListActivity" />
<activity android:name=".activities.NoExtrasActivity" />
<activity android:name=".activities.OptionalActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.juullabs.exercise.annotations.Exercise
import com.juullabs.exercise.fragments.newInstanceOfLegacyFragment
import com.juullabs.exercise.fragments.newInstanceOfListFragment
import com.juullabs.exercise.fragments.newInstanceOfNoExtrasFragment
import com.juullabs.exercise.fragments.newInstanceOfOptionalFragment
import com.juullabs.exercise.fragments.newInstanceOfStandardFragment
import com.juullabs.exercise.fragments.newInstanceOfSubclassFragment
import com.juullabs.exercise.fragments.newLegacyFragment
import com.juullabs.exercise.fragments.newListFragment
import com.juullabs.exercise.fragments.newNoExtrasFragment
import com.juullabs.exercise.fragments.newOptionalFragment
import com.juullabs.exercise.fragments.newStandardFragment
import com.juullabs.exercise.fragments.newSubclassFragment
import kotlinx.android.synthetic.main.activity_fragment_container.showLegacyFragment
import kotlinx.android.synthetic.main.activity_fragment_container.showListFragment
import kotlinx.android.synthetic.main.activity_fragment_container.showNoExtrasFragment
Expand All @@ -20,6 +20,7 @@ import kotlin.random.Random

private const val fragmentTag = "fragmentTag"

@Suppress("DEPRECATION")
@Exercise
class FragmentContainerActivity : AppCompatActivity() {

Expand All @@ -28,33 +29,33 @@ class FragmentContainerActivity : AppCompatActivity() {
setContentView(R.layout.activity_fragment_container)
showLegacyFragment.setOnClickListener {
removeAllFragments()
addLegacyFragment(newInstanceOfLegacyFragment(15))
addLegacyFragment(newLegacyFragment(15))
}
showListFragment.setOnClickListener {
removeAllFragments()
val data = listOf(Datum("First"), Datum("Second"), Datum("Third"))
addFragment(newInstanceOfListFragment(data))
addFragment(newListFragment(data))
}
showNoExtrasFragment.setOnClickListener {
removeAllFragments()
addFragment(newInstanceOfNoExtrasFragment())
addFragment(newNoExtrasFragment())
}
showOptionalFragment.setOnClickListener {
removeAllFragments()
val fragment = if (Random.nextBoolean()) {
newInstanceOfOptionalFragment("Passed a value")
newOptionalFragment("Passed a value")
} else {
newInstanceOfOptionalFragment()
newOptionalFragment()
}
addFragment(fragment)
}
showStandardFragment.setOnClickListener {
removeAllFragments()
addFragment(newInstanceOfStandardFragment(25))
addFragment(newStandardFragment(25))
}
showSubclassFragment.setOnClickListener {
removeAllFragments()
addFragment(newInstanceOfSubclassFragment("super string", "sub string"))
addFragment(newSubclassFragment("super string", "sub string"))
}
showLegacyFragment.performClick()
}
Expand Down
29 changes: 17 additions & 12 deletions application/src/main/java/com/juullabs/exercise/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package com.juullabs.exercise

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.juullabs.exercise.activities.intentForListActivity
import com.juullabs.exercise.activities.intentForNoExtrasActivity
import com.juullabs.exercise.activities.intentForOptionalActivity
import com.juullabs.exercise.activities.intentForStandardActivity
import com.juullabs.exercise.activities.intentForSubclassActivity
import com.juullabs.exercise.activities.CalculatorParentActivityIntent
import com.juullabs.exercise.activities.ListActivityIntent
import com.juullabs.exercise.activities.NoExtrasActivityIntent
import com.juullabs.exercise.activities.OptionalActivityIntent
import com.juullabs.exercise.activities.StandardActivityIntent
import com.juullabs.exercise.activities.SubclassActivityIntent
import kotlinx.android.synthetic.main.activity_main.toCalculatorParentActivity
import kotlinx.android.synthetic.main.activity_main.toFragmentContainer
import kotlinx.android.synthetic.main.activity_main.toListActivity
import kotlinx.android.synthetic.main.activity_main.toNoExtrasActivity
Expand All @@ -21,30 +23,33 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)

toFragmentContainer.setOnClickListener {
startActivity(intentForFragmentContainerActivity())
startActivity(FragmentContainerActivityIntent())
}
toCalculatorParentActivity.setOnClickListener {
startActivity(CalculatorParentActivityIntent())
}
toListActivity.setOnClickListener {
val data = listOf(Datum("First"), Datum("Second"), Datum("Third"))
startActivity(intentForListActivity(data))
startActivity(ListActivityIntent(data))
}
toNoExtrasActivity.setOnClickListener {
startActivity(intentForNoExtrasActivity())
startActivity(NoExtrasActivityIntent())
}
toOptionalActivity.setOnClickListener {
// Optionals have a default value of null.
val intent = if (Random.nextBoolean()) {
intentForOptionalActivity("Passed a value")
OptionalActivityIntent("Passed a value")
} else {
intentForOptionalActivity()
OptionalActivityIntent()
}
startActivity(intent)
}
toStandardActivity.setOnClickListener {
startActivity(intentForStandardActivity(50))
startActivity(StandardActivityIntent(50))
}
toSubclassActivity.setOnClickListener {
startActivity(
intentForSubclassActivity(
SubclassActivityIntent(
superclassString = "super",
subclassString = "sub"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.juullabs.exercise.activities

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.juullabs.exercise.R
import com.juullabs.exercise.annotations.Exercise
import com.juullabs.exercise.annotations.Extra
import com.juullabs.exercise.annotations.ResultContract
import com.juullabs.exercise.annotations.ResultKind
import kotlinx.android.synthetic.main.activity_calc_child.cancel
import kotlinx.android.synthetic.main.activity_calc_child.inputTextView
import kotlinx.android.synthetic.main.activity_calc_child.plus1
import kotlinx.android.synthetic.main.activity_calc_child.times3

@Exercise(Extra("input", Int::class))
@ResultContract(ResultKind("Ok", Extra("output", Int::class)))
class CalculatorChildActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_calc_child)
inputTextView.text = extras.input.toString()
plus1.setOnClickListener { finish(CalculatorChildActivityResult.Ok(extras.input + 1)) }
times3.setOnClickListener { finish(CalculatorChildActivityResult.Ok(extras.input * 3)) }
cancel.setOnClickListener { finish(CalculatorChildActivityResult.Canceled()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.juullabs.exercise.activities

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.juullabs.exercise.R
import com.juullabs.exercise.annotations.Exercise
import kotlinx.android.synthetic.main.activity_calc_parent.initialValue11
import kotlinx.android.synthetic.main.activity_calc_parent.initialValue3
import kotlinx.android.synthetic.main.activity_calc_parent.initialValue5
import kotlinx.android.synthetic.main.activity_calc_parent.initialValue7
import kotlinx.android.synthetic.main.activity_calc_parent.resultTextView

@Exercise
class CalculatorParentActivity : AppCompatActivity() {

private val calculator = prepareCall(CalculatorChildActivityContract()) { result ->
resultTextView.text = when (result) {
null -> "Implicitly canceled"
is CalculatorChildActivityResult.Canceled -> "Explicitly canceled"
is CalculatorChildActivityResult.Ok -> "Result: ${result.output}"
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_calc_parent)
initialValue3.setOnClickListener { calculator.launch(CalculatorChildActivityIntent(3)) }
initialValue5.setOnClickListener { calculator.launch(CalculatorChildActivityIntent(5)) }
initialValue7.setOnClickListener { calculator.launch(CalculatorChildActivityIntent(7)) }
initialValue11.setOnClickListener { calculator.launch(CalculatorChildActivityIntent(11)) }
}

}
31 changes: 31 additions & 0 deletions application/src/main/res/layout/activity_calc_child.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<TextView
android:id="@+id/inputTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<Button
android:id="@+id/plus1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+1" />

<Button
android:id="@+id/times3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="x3" />

<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel" />

</LinearLayout>
Loading

0 comments on commit adf5c24

Please sign in to comment.