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

Migrate DI to KodeinDI #1035

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ maven_install(
"androidx.lifecycle:lifecycle-livedata-ktx:2.2.0",
"androidx.lifecycle:lifecycle-service:2.2.0",
"androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0",
"org.kodein.di:kodein-di:7.11.0",
"org.kodein.di:kodein-di-framework-android-x:7.11.0",
"org.kodein.di:kodein-di-framework-android-x-viewmodel:7.11.0",
],
repositories = DAGGER_REPOSITORIES + [
"https://repo1.maven.org/maven2/",
Expand Down
10 changes: 9 additions & 1 deletion atox/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ android {
}
getByName("release") {
isMinifyEnabled = true
proguardFiles("proguard-tox4j.pro", getDefaultProguardFile("proguard-android-optimize.txt"))
proguardFiles(
"proguard-tox4j.pro",
"proguard-kodein.pro",
getDefaultProguardFile("proguard-android-optimize.txt")
)
}
}
signingConfigs {
Expand Down Expand Up @@ -72,6 +76,10 @@ dependencies {
implementation(libs.androidx.lifecycle.service)
implementation(libs.androidx.lifecycle.viewmodel.ktx)

implementation(libs.kodein.di)
implementation(libs.kodein.di.framework.android.x)
implementation(libs.kodein.di.framework.android.x.viewmodel)

implementation(libs.google.dagger.core)
kapt(libs.google.dagger.compiler)

Expand Down
5 changes: 5 additions & 0 deletions atox/proguard-kodein.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-keep, allowobfuscation, allowoptimization class org.kodein.type.TypeReference
-keep, allowobfuscation, allowoptimization class org.kodein.type.JVMAbstractTypeToken$Companion$WrappingTest

-keep, allowobfuscation, allowoptimization class * extends org.kodein.type.TypeReference
-keep, allowobfuscation, allowoptimization class * extends org.kodein.type.JVMAbstractTypeToken$Companion$WrappingTest
54 changes: 12 additions & 42 deletions atox/src/androidTest/kotlin/IntegrationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package ltd.evilcorp.atox

import android.app.Activity
import android.content.Context
import androidx.room.Room
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
Expand All @@ -19,25 +18,17 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import io.mockk.every
import io.mockk.mockk
import javax.inject.Singleton
import ltd.evilcorp.atox.di.AndroidModule
import ltd.evilcorp.atox.di.AppComponent
import ltd.evilcorp.atox.di.AppModule
import ltd.evilcorp.atox.di.DaoModule
import ltd.evilcorp.atox.di.ViewModelModule
import ltd.evilcorp.core.db.Database
import ltd.evilcorp.domain.tox.PublicKey
import ltd.evilcorp.domain.tox.SaveManager
import org.hamcrest.core.AllOf.allOf
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.kodein.di.DI
import org.kodein.di.bind
import org.kodein.di.instance
import org.kodein.di.singleton

class InjectedActivityTestRule<T : Activity>(
activityClass: Class<T>,
Expand All @@ -49,36 +40,15 @@ class InjectedActivityTestRule<T : Activity>(
}
}

@Module
class TestModule {
@Singleton
@Provides
fun provideDatabase(appContext: Context): Database =
Room.inMemoryDatabaseBuilder(appContext, Database::class.java).build()

@Provides
fun provideSaveManager(): SaveManager = mockk(relaxUnitFun = true) {
every { list() } returns listOf("workaround") // mockk crashes w/ `listOf()`.
every { load(PublicKey("workaround")) } returns null
// Am I using mockk wrong or something? `every { save(any(), any() }` crashes.
}
class SaveManagerImplMock : SaveManager {
override fun list(): List<String> = listOf("workaround")
override fun save(publicKey: PublicKey, saveData: ByteArray) {}
override fun load(publicKey: PublicKey): ByteArray? = null
}

@Singleton
@Component(
modules = [
AppModule::class,
AndroidModule::class,
TestModule::class,
DaoModule::class,
ViewModelModule::class
]
)
interface TestComponent : AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance appContext: Context): AppComponent
}
fun testModule() = DI.Module("TestModule") {
bind(overrides = true) { singleton { Room.inMemoryDatabaseBuilder(instance(), Database::class.java).build() } }
bind<SaveManager>(overrides = true) { singleton { SaveManagerImplMock() } }
}

@RunWith(AndroidJUnit4::class)
Expand All @@ -87,7 +57,7 @@ class IntegrationTest {
val activityRule = InjectedActivityTestRule(MainActivity::class.java) {
val instrumentation = InstrumentationRegistry.getInstrumentation()
val app = instrumentation.targetContext.applicationContext as App
app.componentOverride = DaggerTestComponent.factory().create(app)
app.testModule = testModule()
}

@Test
Expand Down
35 changes: 13 additions & 22 deletions atox/src/main/kotlin/ActionReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import android.util.Log
import android.widget.Toast
import androidx.core.app.RemoteInput
import im.tox.tox4j.av.exceptions.ToxavAnswerException
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.firstOrNull
Expand All @@ -28,6 +27,9 @@ import ltd.evilcorp.domain.feature.ChatManager
import ltd.evilcorp.domain.feature.ContactManager
import ltd.evilcorp.domain.tox.PublicKey
import ltd.evilcorp.domain.tox.Tox
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.instance

const val KEY_TEXT_REPLY = "key_text_reply"
const val KEY_CONTACT_PK = "key_contact_pk"
Expand All @@ -43,30 +45,19 @@ enum class Action {

private const val TAG = "ActionReceiver"

class ActionReceiver : BroadcastReceiver() {
@Inject
lateinit var callManager: CallManager
class ActionReceiver : BroadcastReceiver(), DIAware {
override lateinit var di: DI

@Inject
lateinit var chatManager: ChatManager

@Inject
lateinit var contactManager: ContactManager

@Inject
lateinit var contactRepository: ContactRepository

@Inject
lateinit var notificationHelper: NotificationHelper

@Inject
lateinit var tox: Tox

@Inject
lateinit var scope: CoroutineScope
private val callManager: CallManager by instance()
private val chatManager: ChatManager by instance()
private val contactManager: ContactManager by instance()
private val contactRepository: ContactRepository by instance()
private val notificationHelper: NotificationHelper by instance()
private val tox: Tox by instance()
private val scope: CoroutineScope by instance()

override fun onReceive(context: Context, intent: Intent) {
(context.applicationContext as App).component.inject(this)
di = (context.applicationContext as DIAware).di

scope.launch {
val pk = intent.getStringExtra(KEY_CONTACT_PK)?.let { PublicKey(it) }
Expand Down
34 changes: 25 additions & 9 deletions atox/src/main/kotlin/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@

package ltd.evilcorp.atox

import androidx.annotation.VisibleForTesting
import androidx.multidex.MultiDexApplication
import ltd.evilcorp.atox.di.AppComponent
import ltd.evilcorp.atox.di.DaggerAppComponent
import ltd.evilcorp.atox.di.appModule
import ltd.evilcorp.atox.di.coreModule
import ltd.evilcorp.atox.di.daoModule
import ltd.evilcorp.atox.di.databaseModule
import ltd.evilcorp.atox.di.domainModule
import ltd.evilcorp.atox.di.viewModelModule
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.android.x.androidXModule
import org.kodein.di.diContext

class App : MultiDexApplication() {
val component: AppComponent by lazy {
componentOverride ?: DaggerAppComponent.factory().create(applicationContext)
}
class App : MultiDexApplication(), DIAware {
var testModule: DI.Module? = null

override val di by DI.lazy {
importOnce(androidXModule(this@App))
importOnce(appModule(diContext(this@App)))
importOnce(coreModule())
importOnce(daoModule())
importOnce(databaseModule())
importOnce(domainModule(diContext(this@App)))
importOnce(viewModelModule(this@App))

@VisibleForTesting
var componentOverride: AppComponent? = null
testModule?.let {
import(it, allowOverride = true)
}
}
}
18 changes: 9 additions & 9 deletions atox/src/main/kotlin/AutoAway.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ package ltd.evilcorp.atox

import android.util.Log
import java.util.Timer
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.concurrent.schedule
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import ltd.evilcorp.atox.settings.Settings
import ltd.evilcorp.core.vo.UserStatus
import ltd.evilcorp.domain.feature.UserManager
import ltd.evilcorp.domain.tox.Tox
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.instance

private const val TAG = "AutoAway"

@Singleton
class AutoAway @Inject constructor(
private val scope: CoroutineScope,
private val settings: Settings,
private val userManager: UserManager,
private val tox: Tox
) {
class AutoAway(override val di: DI) : DIAware {
private val scope: CoroutineScope by instance()
private val settings: Settings by instance()
private val userManager: UserManager by instance()
private val tox: Tox by instance()

private var awayTimer = Timer()
private var autoAway = false

Expand Down
13 changes: 8 additions & 5 deletions atox/src/main/kotlin/BootReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.navigation.NavDeepLinkBuilder
import javax.inject.Inject
import ltd.evilcorp.atox.tox.ToxStarter
import ltd.evilcorp.domain.tox.ToxSaveStatus
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.instance

private const val ENCRYPTED = "aTox profile encrypted"

class BootReceiver : BroadcastReceiver() {
@Inject
lateinit var toxStarter: ToxStarter
class BootReceiver : BroadcastReceiver(), DIAware {
override lateinit var di: DI

private val toxStarter: ToxStarter by instance()

override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
(context.applicationContext as App).component.inject(this)
di = (context.applicationContext as DIAware).di
if (toxStarter.tryLoadTox(null) == ToxSaveStatus.Encrypted) {
val channel = NotificationChannelCompat.Builder(ENCRYPTED, NotificationManagerCompat.IMPORTANCE_HIGH)
.setName(context.getString(R.string.atox_profile_locked))
Expand Down
4 changes: 0 additions & 4 deletions atox/src/main/kotlin/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@ import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import ltd.evilcorp.atox.di.ViewModelFactory

fun Context.hasPermission(permission: String) =
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED

val Fragment.vmFactory: ViewModelFactory
get() = (requireActivity() as MainActivity).vmFactory

class NoSuchArgumentException(arg: String) : Exception("No such argument: $arg")

fun Fragment.requireStringArg(key: String) =
Expand Down
19 changes: 7 additions & 12 deletions atox/src/main/kotlin/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,23 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.bundleOf
import androidx.core.view.WindowCompat
import androidx.navigation.fragment.findNavController
import javax.inject.Inject
import ltd.evilcorp.atox.di.ViewModelFactory
import ltd.evilcorp.atox.settings.Settings
import ltd.evilcorp.atox.ui.contactlist.ARG_SHARE
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance

private const val TAG = "MainActivity"
private const val SCHEME = "tox:"
private const val TOX_ID_LENGTH = 76

class MainActivity : AppCompatActivity() {
@Inject
lateinit var vmFactory: ViewModelFactory
class MainActivity : AppCompatActivity(), DIAware {
override val di by closestDI()

@Inject
lateinit var autoAway: AutoAway

@Inject
lateinit var settings: Settings
private val autoAway: AutoAway by instance()
private val settings: Settings by instance()

override fun onCreate(savedInstanceState: Bundle?) {
(application as App).component.inject(this)

super.onCreate(savedInstanceState)

if (settings.disableScreenshots) {
Expand Down
Loading