Skip to content

Commit

Permalink
Merge pull request #1515 from CruGlobal/daggerHiltViewModels
Browse files Browse the repository at this point in the history
GT-1064 Update dagger hilt ViewModel support
  • Loading branch information
frett committed Jan 29, 2021
2 parents 6e510c8 + 4d5ffe2 commit ec5386f
Show file tree
Hide file tree
Showing 26 changed files with 136 additions and 138 deletions.
2 changes: 0 additions & 2 deletions app/build.gradle
Expand Up @@ -169,7 +169,6 @@ dependencies {

implementation "androidx.constraintlayout:constraintlayout:${deps.androidX.constraintLayout}"
implementation "androidx.fragment:fragment-ktx:${deps.androidX.fragment}"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:${deps.androidX.hilt}"
implementation "androidx.lifecycle:lifecycle-extensions:${deps.androidX.lifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${deps.androidX.lifecycle}"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:${deps.androidX.swipeRefreshLayout}"
Expand Down Expand Up @@ -220,7 +219,6 @@ dependencies {
debugImplementation 'com.facebook.soloader:soloader:0.9.0'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${deps.leakcanary}"

kapt "androidx.hilt:hilt-compiler:${deps.androidX.hilt}"
kapt "com.google.dagger:dagger-compiler:${deps.dagger}"
kapt "com.google.dagger:hilt-compiler:${deps.hilt}"
kapt "org.greenrobot:eventbus-annotation-processor:${deps.eventbus}"
Expand Down
Expand Up @@ -2,10 +2,11 @@ package org.cru.godtools.ui.languages

import android.os.Bundle
import androidx.fragment.app.viewModels
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel
import androidx.lifecycle.switchMap
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import org.ccci.gto.android.common.androidx.lifecycle.orEmpty
import org.ccci.gto.android.common.db.findLiveData
import org.cru.godtools.R
Expand Down Expand Up @@ -34,7 +35,8 @@ class LanguageSettingsFragment :
override fun editParallelLanguage() = requireActivity().startLanguageSelectionActivity(false)
}

class LanguageSettingsFragmentDataModel @ViewModelInject constructor(dao: GodToolsDao, settings: Settings) :
@HiltViewModel
class LanguageSettingsFragmentDataModel @Inject constructor(dao: GodToolsDao, settings: Settings) :
ViewModel() {
val primaryLanguage = settings.primaryLanguageLiveData.switchMap { dao.findLiveData<Language>(it) }
val parallelLanguage =
Expand Down
@@ -1,17 +1,17 @@
package org.cru.godtools.ui.languages

import android.content.Context
import androidx.hilt.Assisted
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.switchMap
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import java.text.Collator
import java.util.Locale
import javax.inject.Inject
import org.ccci.gto.android.common.androidx.lifecycle.combineWith
import org.ccci.gto.android.common.db.Query
import org.ccci.gto.android.common.db.getAsLiveData
Expand All @@ -23,11 +23,12 @@ import org.keynote.godtools.android.db.GodToolsDao
private const val KEY_QUERY = "query"
private const val KEY_IS_SEARCH_VIEW_OPEN = "isSearchViewOpen"

class LanguagesFragmentViewModel @ViewModelInject constructor(
@HiltViewModel
class LanguagesFragmentViewModel @Inject constructor(
@ApplicationContext context: Context,
dao: GodToolsDao,
settings: Settings,
@Assisted private val savedState: SavedStateHandle
private val savedState: SavedStateHandle
) : ViewModel() {
val isPrimary = MutableLiveData(true)

Expand Down
Expand Up @@ -2,9 +2,10 @@ package org.cru.godtools.ui.profile

import android.os.Bundle
import androidx.fragment.app.viewModels
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import org.ccci.gto.android.common.db.findLiveData
import org.ccci.gto.android.common.sync.swiperefreshlayout.widget.SwipeRefreshSyncHelper
import org.cru.godtools.R
Expand All @@ -28,6 +29,7 @@ class GlobalActivityFragment :
}
}

class GlobalActivityFragmentViewModel @ViewModelInject constructor(dao: GodToolsDao) : ViewModel() {
@HiltViewModel
class GlobalActivityFragmentViewModel @Inject constructor(dao: GodToolsDao) : ViewModel() {
val globalActivity = dao.findLiveData<GlobalActivityAnalytics>(1)
}
@@ -1,12 +1,13 @@
package org.cru.godtools.ui.tooldetails

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.map
import androidx.lifecycle.switchMap
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import org.ccci.gto.android.common.androidx.lifecycle.emptyLiveData
import org.ccci.gto.android.common.androidx.lifecycle.orEmpty
import org.ccci.gto.android.common.androidx.lifecycle.switchCombineWith
Expand All @@ -23,7 +24,8 @@ import org.cru.godtools.shortcuts.GodToolsShortcutManager
import org.keynote.godtools.android.db.Contract.TranslationTable
import org.keynote.godtools.android.db.GodToolsDao

class ToolDetailsFragmentDataModel @ViewModelInject constructor(
@HiltViewModel
class ToolDetailsFragmentDataModel @Inject constructor(
private val dao: GodToolsDao,
private val downloadManager: GodToolsDownloadManager,
manifestManager: ManifestManager,
Expand Down
20 changes: 9 additions & 11 deletions app/src/main/java/org/cru/godtools/ui/tools/ToolsAdapter.kt
Expand Up @@ -17,16 +17,16 @@ import org.ccci.gto.android.common.recyclerview.advrecyclerview.draggable.Simple
import org.cru.godtools.databinding.ToolsListItemToolBinding
import org.cru.godtools.model.Tool

private const val VIEW_MODEL_KEY_PREFIX =
"org.cru.godtools.ui.tools.ToolsAdapter:org.cru.godtools.ui.tools.ToolsAdapterToolViewModel"
private typealias VH = DataBindingDraggableItemViewHolder<ToolsListItemToolBinding>

class ToolsAdapter(lifecycleOwner: LifecycleOwner, private val viewModelProvider: ViewModelProvider) :
class ToolsAdapter(lifecycleOwner: LifecycleOwner, viewModelProvider: ViewModelProvider) :
SimpleDataBindingDraggableItemAdapter<ToolsListItemToolBinding>(lifecycleOwner), Observer<List<Tool>> {
init {
setHasStableIds(true)
}

private val viewModel = viewModelProvider.get(ToolsAdapterViewModel::class.java)

val callbacks = ObservableField<ToolsAdapterCallbacks>()
private var tools: List<Tool>? = null
set(value) {
Expand Down Expand Up @@ -54,16 +54,14 @@ class ToolsAdapter(lifecycleOwner: LifecycleOwner, private val viewModelProvider

override fun onBindViewDataBinding(binding: ToolsListItemToolBinding, position: Int) {
val tool = getItem(position)
val code = tool?.code
val viewModel = viewModelProvider.get("$VIEW_MODEL_KEY_PREFIX:$code", ToolsAdapterToolViewModel::class.java)
.also { it.toolCode.value = code }
val toolViewModel = tool?.code?.let { viewModel.getToolViewModel(it) }

binding.tool = tool
binding.setDownloadProgress(viewModel.downloadProgress)
binding.setBanner(viewModel.banner)
binding.primaryTranslation = viewModel.firstTranslation
binding.parallelTranslation = viewModel.parallelTranslation
binding.parallelLanguage = viewModel.parallelLanguage
binding.setDownloadProgress(toolViewModel?.downloadProgress)
binding.setBanner(toolViewModel?.banner)
binding.primaryTranslation = toolViewModel?.firstTranslation
binding.parallelTranslation = toolViewModel?.parallelTranslation
binding.parallelLanguage = toolViewModel?.parallelLanguage
}

override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
Expand Down

This file was deleted.

@@ -0,0 +1,65 @@
package org.cru.godtools.ui.tools

import androidx.lifecycle.ViewModel
import androidx.lifecycle.map
import androidx.lifecycle.switchMap
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import org.ccci.gto.android.common.androidx.lifecycle.combineWith
import org.ccci.gto.android.common.androidx.lifecycle.emptyLiveData
import org.ccci.gto.android.common.androidx.lifecycle.orEmpty
import org.ccci.gto.android.common.androidx.lifecycle.switchCombineWith
import org.ccci.gto.android.common.db.Query
import org.ccci.gto.android.common.db.findLiveData
import org.ccci.gto.android.common.db.getAsLiveData
import org.cru.godtools.base.Settings
import org.cru.godtools.download.manager.GodToolsDownloadManager
import org.cru.godtools.model.Attachment
import org.cru.godtools.model.Language
import org.keynote.godtools.android.db.Contract.AttachmentTable
import org.keynote.godtools.android.db.Contract.ToolTable
import org.keynote.godtools.android.db.GodToolsDao

@HiltViewModel
class ToolsAdapterViewModel @Inject constructor(
private val dao: GodToolsDao,
private val downloadManager: GodToolsDownloadManager,
private val settings: Settings
) : ViewModel() {
private val toolViewModels = mutableMapOf<String, ToolViewModel>()
fun getToolViewModel(tool: String) = toolViewModels.getOrPut(tool) { ToolViewModel(tool) }

inner class ToolViewModel(private val tool: String) {
val banner = Query.select<Attachment>()
.join(AttachmentTable.SQL_JOIN_TOOL)
.where(
ToolTable.FIELD_CODE.eq(tool)
.and(ToolTable.FIELD_BANNER.eq(AttachmentTable.FIELD_ID))
.and(AttachmentTable.SQL_WHERE_DOWNLOADED)
)
.limit(1)
.getAsLiveData(dao)
.map { it.firstOrNull() }

private val primaryTranslation =
settings.primaryLanguageLiveData.switchMap { dao.getLatestTranslationLiveData(tool, it) }
private val defaultTranslation = dao.getLatestTranslationLiveData(tool, Settings.defaultLanguage)
internal val firstTranslation = primaryTranslation.combineWith(defaultTranslation) { p, d -> p ?: d }
internal val parallelTranslation =
settings.parallelLanguageLiveData.switchMap { dao.getLatestTranslationLiveData(tool, it) }

internal val parallelLanguage = parallelTranslation.switchMap { t ->
t?.languageCode?.let { dao.findLiveData<Language>(it) }.orEmpty()
}

internal val downloadProgress =
primaryTranslation.switchCombineWith(defaultTranslation, parallelTranslation) { prim, def, para ->
when {
prim != null -> downloadManager.getDownloadProgressLiveData(tool, prim.languageCode)
def != null -> downloadManager.getDownloadProgressLiveData(tool, def.languageCode)
para != null -> downloadManager.getDownloadProgressLiveData(tool, para.languageCode)
else -> emptyLiveData()
}
}
}
}
@@ -1,11 +1,12 @@
package org.cru.godtools.ui.tools

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.switchMap
import dagger.hilt.android.lifecycle.HiltViewModel
import java.util.Locale
import javax.inject.Inject
import org.ccci.gto.android.common.androidx.lifecycle.combineWith
import org.ccci.gto.android.common.db.Query
import org.ccci.gto.android.common.db.getAsLiveData
Expand All @@ -20,7 +21,8 @@ import org.cru.godtools.widget.BannerType
import org.keynote.godtools.android.db.Contract.ToolTable
import org.keynote.godtools.android.db.GodToolsDao

class ToolsFragmentDataModel @ViewModelInject constructor(private val dao: GodToolsDao, settings: Settings) :
@HiltViewModel
class ToolsFragmentDataModel @Inject constructor(private val dao: GodToolsDao, settings: Settings) :
ViewModel() {
val mode = MutableLiveData(MODE_ADDED)

Expand Down
Expand Up @@ -17,7 +17,6 @@ import org.cru.godtools.model.Language
import org.cru.godtools.model.Tool
import org.cru.godtools.model.Translation
import org.cru.godtools.ui.tools.ToolsAdapterCallbacks
import org.cru.godtools.ui.tools.ToolsAdapterToolViewModel
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
Expand All @@ -33,7 +32,6 @@ import org.robolectric.annotation.Config
class ToolsListItemToolBindingTest {
private lateinit var binding: ToolsListItemToolBinding
private lateinit var callbacks: ToolsAdapterCallbacks
private lateinit var viewModel: ToolsAdapterToolViewModel
private val tool = Tool().apply {
type = Tool.Type.TRACT
code = "test"
Expand All @@ -56,7 +54,6 @@ class ToolsListItemToolBindingTest {
fun createBinding() {
val activityController = Robolectric.buildActivity(MainActivity::class.java)
callbacks = mock()
viewModel = mock()

binding = ToolsListItemToolBinding.inflate(LayoutInflater.from(activityController.get()), null, false)
binding.lifecycleOwner = activityController.get()
Expand Down
3 changes: 1 addition & 2 deletions build.gradle
Expand Up @@ -18,7 +18,7 @@ buildscript {
gtoSupport : '3.7.2-SNAPSHOT',
guava : '30.1-android',
hamcrest : '2.2',
hilt : '2.30.1-alpha',
hilt : '2.31.2-alpha',
jacoco : '0.8.6',
jsoup : '1.13.1',
junit : '4.13.1',
Expand Down Expand Up @@ -59,7 +59,6 @@ buildscript {
core : '1.3.2',
databinding : deps.gradleAndroidPlugin,
fragment : '1.2.5',
hilt : '1.0.0-alpha02',
lifecycle : '2.2.0',
loader : '1.1.0',
multidex : '2.0.1',
Expand Down
3 changes: 0 additions & 3 deletions library/analytics/build.gradle
Expand Up @@ -30,8 +30,6 @@ dependencies {

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${deps.kotlinCoroutines}"

implementation "androidx.hilt:hilt-lifecycle-viewmodel:${deps.androidX.hilt}"

implementation "com.google.firebase:firebase-core:${deps.firebase.core}"
implementation "com.google.firebase:firebase-messaging:${deps.firebase.messaging}"
implementation "com.google.firebase:firebase-perf:${deps.firebase.perf}"
Expand All @@ -56,7 +54,6 @@ dependencies {

testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:${deps.kotlinCoroutines}"

kapt "androidx.hilt:hilt-compiler:${deps.androidX.hilt}"
kapt "com.google.dagger:dagger-compiler:${deps.dagger}"
kapt "com.google.dagger:hilt-compiler:${deps.hilt}"
kapt "org.greenrobot:eventbus-annotation-processor:${deps.eventbus}"
Expand Down

0 comments on commit ec5386f

Please sign in to comment.