Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Kotlin Extensions for Toothpick #324

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions deps.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,28 @@ ext.deps = [// Common
coverallPlugin : 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.6.3',
supportv4 : 'com.android.support:support-v4:28.0.0',
androidxv4 : 'androidx.legacy:legacy-support-v4:1.0.0',
androidxAppCompat : 'androidx.appcompat:appcompat:1.1.0-alpha01',
butterknife : 'com.jakewharton:butterknife:10.0.0',
butterknife_compiler: 'com.jakewharton:butterknife-compiler:10.0.0',
rxandroid : 'io.reactivex:rxandroid:1.2.1',

// Kotlin
kotlin_plugin : 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20',
kotlin_stdlib : 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.20',
kotlin_reflect : 'org.jetbrains.kotlin:kotlin-reflect:1.3.20',

// TP artifacts for composite builds
tp_smoothie : 'com.github.stephanenicolas.toothpick:smoothie:2.0.0',
tp_smoothie_androidx: 'com.github.stephanenicolas.toothpick:smoothie-androidx:2.0.0',
tp_smoothie_support : 'com.github.stephanenicolas.toothpick:smoothie-support:2.0.0',
tp : 'com.github.stephanenicolas.toothpick:toothpick:2.0.0',
tp_runtime : 'com.github.stephanenicolas.toothpick:toothpick-runtime:2.0.0',
tp_compiler : 'com.github.stephanenicolas.toothpick:toothpick-compiler:2.0.0',
tp_testing : 'com.github.stephanenicolas.toothpick:toothpick-testing:2.0.0',
tp_testing_junit4 : 'com.github.stephanenicolas.toothpick:toothpick-testing-junit4:2.0.0',
tp_testing_junit5 : 'com.github.stephanenicolas.toothpick:toothpick-testing-junit5:2.0.0',
tp_smoothie : "com.github.stephanenicolas.toothpick:smoothie:${project.findProperty('VERSION_NAME')}",
tp_smoothie_androidx: "com.github.stephanenicolas.toothpick:smoothie-androidx:${project.findProperty('VERSION_NAME')}",
tp_smoothie_support : "com.github.stephanenicolas.toothpick:smoothie-support:${project.findProperty('VERSION_NAME')}",
tp : "com.github.stephanenicolas.toothpick:toothpick:${project.findProperty('VERSION_NAME')}",
tp_runtime : "com.github.stephanenicolas.toothpick:toothpick-runtime:${project.findProperty('VERSION_NAME')}",
tp_compiler : "com.github.stephanenicolas.toothpick:toothpick-compiler:${project.findProperty('VERSION_NAME')}",
tp_kotlin : "com.github.stephanenicolas.toothpick:toothpick-kotlin:${project.findProperty('VERSION_NAME')}",
tp_kotlin_androidx : "com.github.stephanenicolas.toothpick:toothpick-kotlin-androidx:${project.findProperty('VERSION_NAME')}",
tp_testing : "com.github.stephanenicolas.toothpick:toothpick-testing:${project.findProperty('VERSION_NAME')}",
tp_testing_junit4 : "com.github.stephanenicolas.toothpick:toothpick-testing-junit4:${project.findProperty('VERSION_NAME')}",
tp_testing_junit5 : "com.github.stephanenicolas.toothpick:toothpick-testing-junit5:${project.findProperty('VERSION_NAME')}",

// Test dependencies
junit4 : 'junit:junit:4.12',
Expand All @@ -39,4 +47,4 @@ ext.deps = [// Common

// Android Test Dependencies
espresso : 'com.android.support.test.espresso:espresso-core:2.2.2',
dexmaker : 'com.google.dexmaker:dexmaker:1.2',]
dexmaker : 'com.google.dexmaker:dexmaker:1.2',]
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
include ':toothpick'
include ':toothpick-javax-annotations'
include ':toothpick-compiler'
include ':toothpick-kotlin'
include ':toothpick-kotlin-androidx'
include ':toothpick-runtime'
include ':toothpick-testing'
include ':toothpick-testing-junit4'
Expand Down
18 changes: 16 additions & 2 deletions smoothie-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ buildscript {
}
dependencies {
classpath deps.androidPlugin
classpath deps.kotlin_plugin
}
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 28
Expand Down Expand Up @@ -53,12 +56,17 @@ repositories {
dependencies {
implementation deps.tp_smoothie_androidx
implementation deps.tp_runtime
implementation deps.tp_kotlin
implementation deps.tp_kotlin_androidx
implementation deps.butterknife
implementation deps.rxandroid
implementation deps.androidxv4

annotationProcessor deps.tp_compiler
annotationProcessor deps.butterknife_compiler
implementation deps.kotlin_stdlib
implementation deps.kotlin_reflect

kapt deps.tp_compiler
kapt deps.butterknife_compiler

testImplementation deps.tp_testing_junit4
testImplementation deps.junit4
Expand All @@ -70,3 +78,9 @@ dependencies {
androidTestImplementation deps.easymock
androidTestImplementation deps.dexmaker
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use Task Configuration Avoidance.

kotlinOptions {
jvmTarget = "1.8"
}
}
11 changes: 10 additions & 1 deletion smoothie-sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,14 @@
android:name=".PersistActivity"/>
<activity
android:name=".LessSimpleActivity"/>

<activity
android:name=".kotlin.SimpleActivity"/>
<activity
android:name=".kotlin.RxMVPActivity"/>
<activity
android:name=".kotlin.PersistActivity"/>
<activity
android:name=".kotlin.LessSimpleActivity"/>
</application>
</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ protected void onDestroy() {
Toothpick.closeScope(this);
super.onDestroy();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.smoothie.kotlin

import android.accounts.AccountManager
import android.app.Activity
import android.app.AlarmManager
import android.app.Application
import android.content.SharedPreferences
import android.os.Bundle
import android.widget.TextView
import androidx.fragment.app.FragmentManager
import butterknife.ButterKnife
import com.example.smoothie.R
import com.example.smoothie.kotlin.deps.ContextNamer
import toothpick.Toothpick
import toothpick.kotlin.androidx.inject
import toothpick.kotlin.module
import toothpick.kotlin.providedBy
import toothpick.smoothie.module.SmoothieActivityModule

class LessSimpleActivity : Activity() {
// inject() will attempt to find a scope, then default to this activity instance
private val injectedApplication: Application by inject()
private val accountManager: AccountManager by inject()
private val sharedPreferences: SharedPreferences by inject()
private val alarmManager: AlarmManager by inject()
private val injectFragmentManager: FragmentManager by inject()
private val activity: Activity by inject()
private val contextNamer: ContextNamer by inject()
private val specialString: String by inject(name = "SpecialString")

private val title by lazy { findViewById<TextView>(R.id.title) }
private val subTitle by lazy { findViewById<TextView>(R.id.subtitle) }

override fun onCreate(savedInstanceState: Bundle?) {
val scope = Toothpick.openScopes(application, this)
scope.installModules(SmoothieActivityModule(this))
scope.installModules(module { String::class named "SpecialString" providedBy "My Special String" })
super.onCreate(savedInstanceState)
setContentView(R.layout.simple_activity)
ButterKnife.bind(this)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need butterknife ? It seems to me we're using a simple lazy to assign the views.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, was just copying the Java examples over for parity.

title.text = "${contextNamer.applicationName} with $specialString"
subTitle.text = contextNamer.activityName
}

override fun onDestroy() {
Toothpick.closeScope(this)
super.onDestroy()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.smoothie.kotlin

import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import butterknife.ButterKnife
import com.example.smoothie.R
import com.example.smoothie.kotlin.deps.PresenterContextNamer
import toothpick.Scope
import toothpick.Toothpick
import toothpick.kotlin.HasScope
import toothpick.kotlin.androidx.inject
import toothpick.kotlin.injectLazy
import toothpick.smoothie.module.SmoothieActivityModule

class PersistActivity : Activity(), HasScope {
override lateinit var scope: Scope

// inject() will use HasScope interface to use to correct scope with presenter scope
private val contextNamer: PresenterContextNamer by inject()

private val title by lazy { findViewById<TextView>(R.id.title) }
private val subTitle by lazy { findViewById<TextView>(R.id.subtitle) }
private val button by lazy { findViewById<Button>(R.id.hello) }

override fun onCreate(savedInstanceState: Bundle?) {
scope = Toothpick.openScopes(application, PRESENTER_SCOPE, this)
scope.installModules(SmoothieActivityModule(this))
super.onCreate(savedInstanceState)

setContentView(R.layout.simple_activity)
ButterKnife.bind(this)
title.text = "MVP"
subTitle.text = contextNamer.instanceCount
button.visibility = View.GONE
}

override fun onDestroy() {
Toothpick.closeScope(this)
super.onDestroy()
}

override fun onBackPressed() {
//when we leave the presenter flow,
//we close its scope
Toothpick.closeScope(PRESENTER_SCOPE)
super.onBackPressed()
}

@Target(AnnotationTarget.CLASS)
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@javax.inject.Scope
annotation class Presenter

companion object {
val PRESENTER_SCOPE: Class<*> = Presenter::class.java
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.smoothie.kotlin

import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import com.example.smoothie.R
import com.example.smoothie.kotlin.deps.RxPresenter
import rx.Subscription
import rx.functions.Action1
import toothpick.Scope
import toothpick.Toothpick
import toothpick.kotlin.injectLazy
import toothpick.smoothie.module.SmoothieActivityModule

class RxMVPActivity : Activity() {
private lateinit var activityScope: Scope

// Uses lazy assign of scope via InjectConfig block and default TP Kotlin Extension
private val rxPresenter: RxPresenter by injectLazy { scope = activityScope }

private val title by lazy { findViewById<TextView>(R.id.title) }
private val subTitle by lazy { findViewById<TextView>(R.id.subtitle) }
private val button by lazy { findViewById<Button>(R.id.hello) }

private lateinit var subscription: Subscription

override fun onCreate(savedInstanceState: Bundle?) {
activityScope = Toothpick.openScopes(application, PRESENTER_SCOPE, this)
activityScope.installModules(SmoothieActivityModule(this))
super.onCreate(savedInstanceState)

setContentView(R.layout.simple_activity)
title.text = "MVP"
subscription = rxPresenter.subscribe(Action1 { aLong -> subTitle.text = aLong.toString() } )
button.visibility = View.GONE
}

override fun onDestroy() {
Toothpick.closeScope(this)
subscription.unsubscribe()
if (isFinishing) {
//when we leave the presenter flow,
//we close its scope
rxPresenter.stop()
Toothpick.closeScope(PRESENTER_SCOPE)
}
super.onDestroy()
}

@Target(AnnotationTarget.CLASS)
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@javax.inject.Scope
annotation class Presenter

companion object {
val PRESENTER_SCOPE: Class<*> = Presenter::class.java
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.smoothie.kotlin

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import com.example.smoothie.R
import com.example.smoothie.kotlin.deps.ContextNamer
import toothpick.Toothpick
import toothpick.kotlin.androidx.inject
import toothpick.smoothie.module.SmoothieAndroidXActivityModule

class SimpleActivity : FragmentActivity() {
// Will use activity instance as scope
private val contextNamer: ContextNamer by inject()

private val title by lazy { findViewById<TextView>(R.id.title) }
private val subTitle by lazy { findViewById<TextView>(R.id.subtitle) }
private val button by lazy { findViewById<Button>(R.id.hello) }

override fun onCreate(savedInstanceState: Bundle?) {
val scope = Toothpick.openScopes(application, this)
scope.installModules(SmoothieAndroidXActivityModule(this))
super.onCreate(savedInstanceState)
setContentView(R.layout.simple_activity)

title.text = contextNamer.applicationName
subTitle.text = contextNamer.activityName
button.apply {
text = "click me !"
setOnClickListener { startActivity(Intent(this@SimpleActivity, RxMVPActivity::class.java)) }
}
}

override fun onDestroy() {
Toothpick.closeScope(this)
super.onDestroy()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.smoothie.kotlin.deps

import android.app.Activity
import android.app.Application
import javax.inject.Inject

class ContextNamer @Inject constructor(
application: Application,
activity: Activity
) {
val applicationName = application::class.simpleName ?: ""
val activityName = activity::class.simpleName ?: ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.smoothie.kotlin.deps

import com.example.smoothie.kotlin.PersistActivity
import javax.inject.Inject

@PersistActivity.Presenter
class PresenterContextNamer @Inject constructor() {

init {
countInstances++
}

val instanceCount: String
get() = "Instance# $countInstances"

companion object {
private var countInstances = 0
}
}
Loading