Replace Picasso with Glide

This commit is contained in:
Kirill Kamakin
2022-04-18 13:17:07 +02:00
parent 96bce0e5f4
commit 2686f757ea
19 changed files with 99 additions and 122 deletions

View File

@@ -148,8 +148,9 @@ dependencies {
// https://github.com/Kotlin/kotlinx-datetime/releases // https://github.com/Kotlin/kotlinx-datetime/releases
implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.3.1" implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.3.1"
// https://github.com/square/picasso/releases // https://github.com/bumptech/glide/releases
implementation "com.squareup.picasso:picasso:2.8" def glide_version = "4.13.1"
implementation "com.github.bumptech.glide:glide:$glide_version"
// https://github.com/androidbroadcast/ViewBindingPropertyDelegate/releases // https://github.com/androidbroadcast/ViewBindingPropertyDelegate/releases
implementation "com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.6" implementation "com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.6"

View File

@@ -48,3 +48,12 @@
-dontwarn org.bouncycastle.** -dontwarn org.bouncycastle.**
-dontwarn org.openjsse.** -dontwarn org.openjsse.**
### OkHttp warnings ### ### OkHttp warnings ###
### Glide https://bumptech.github.io/glide/doc/download-setup.html#proguard ###
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
### Glide https://bumptech.github.io/glide/doc/download-setup.html#proguard ###

View File

@@ -4,6 +4,7 @@
package="gq.kirmanak.mealient"> package="gq.kirmanak.mealient">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application <application
android:name="gq.kirmanak.mealient.App" android:name="gq.kirmanak.mealient.App"

View File

@@ -2,24 +2,29 @@ package gq.kirmanak.mealient.data.recipes.impl
import android.widget.ImageView import android.widget.ImageView
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
import dagger.hilt.android.scopes.FragmentScoped
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.data.baseurl.BaseURLStorage import gq.kirmanak.mealient.data.baseurl.BaseURLStorage
import gq.kirmanak.mealient.extensions.launchWhenViewResumed
import gq.kirmanak.mealient.ui.images.ImageLoader import gq.kirmanak.mealient.ui.images.ImageLoader
import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton
@Singleton @FragmentScoped
class RecipeImageLoaderImpl @Inject constructor( class RecipeImageLoaderImpl @Inject constructor(
private val imageLoader: ImageLoader, private val imageLoader: ImageLoader,
private val baseURLStorage: BaseURLStorage, private val baseURLStorage: BaseURLStorage,
private val fragment: Fragment,
): RecipeImageLoader { ): RecipeImageLoader {
override suspend fun loadRecipeImage(view: ImageView, slug: String?) { override fun loadRecipeImage(view: ImageView, slug: String?) {
Timber.v("loadRecipeImage() called with: view = $view, slug = $slug") Timber.v("loadRecipeImage() called with: view = $view, slug = $slug")
imageLoader.loadImage(generateImageUrl(slug), R.drawable.placeholder_recipe, view) fragment.launchWhenViewResumed {
imageLoader.loadImage(generateImageUrl(slug), R.drawable.placeholder_recipe, view)
}
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -13,12 +13,10 @@ import gq.kirmanak.mealient.data.network.createServiceFactory
import gq.kirmanak.mealient.data.recipes.RecipeRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
import gq.kirmanak.mealient.data.recipes.db.RecipeStorageImpl import gq.kirmanak.mealient.data.recipes.db.RecipeStorageImpl
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageLoaderImpl
import gq.kirmanak.mealient.data.recipes.impl.RecipeRepoImpl import gq.kirmanak.mealient.data.recipes.impl.RecipeRepoImpl
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSourceImpl import gq.kirmanak.mealient.data.recipes.network.RecipeDataSourceImpl
import gq.kirmanak.mealient.data.recipes.network.RecipeService import gq.kirmanak.mealient.data.recipes.network.RecipeService
import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import javax.inject.Named import javax.inject.Named
@@ -40,10 +38,6 @@ interface RecipeModule {
@Singleton @Singleton
fun provideRecipeRepo(recipeRepoImpl: RecipeRepoImpl): RecipeRepo fun provideRecipeRepo(recipeRepoImpl: RecipeRepoImpl): RecipeRepo
@Binds
@Singleton
fun provideRecipeImageLoader(recipeImageLoaderImpl: RecipeImageLoaderImpl): RecipeImageLoader
companion object { companion object {
@Provides @Provides

View File

@@ -1,27 +1,25 @@
package gq.kirmanak.mealient.di package gq.kirmanak.mealient.di
import com.squareup.picasso.Picasso
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.android.components.FragmentComponent
import dagger.hilt.android.scopes.FragmentScoped
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageLoaderImpl
import gq.kirmanak.mealient.ui.images.ImageLoader import gq.kirmanak.mealient.ui.images.ImageLoader
import gq.kirmanak.mealient.ui.images.ImageLoaderPicasso import gq.kirmanak.mealient.ui.images.ImageLoaderGlide
import gq.kirmanak.mealient.ui.images.PicassoBuilder import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader
import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(FragmentComponent::class)
interface UiModule { interface UiModule {
@Binds @Binds
@Singleton @FragmentScoped
fun bindImageLoader(imageLoaderGlide: ImageLoaderPicasso): ImageLoader fun bindImageLoader(imageLoaderGlide: ImageLoaderGlide): ImageLoader
@Binds
@FragmentScoped
fun provideRecipeImageLoader(recipeImageLoaderImpl: RecipeImageLoaderImpl): RecipeImageLoader
companion object {
@Provides
@Singleton
fun providePicasso(picassoBuilder: PicassoBuilder): Picasso = picassoBuilder.buildPicasso()
}
} }

View File

@@ -2,11 +2,15 @@ package gq.kirmanak.mealient.extensions
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
inline fun <T> Fragment.collectWithViewLifecycle( inline fun <T> Fragment.collectWhenViewResumed(
flow: Flow<T>, flow: Flow<T>,
crossinline collector: suspend (T) -> Unit, crossinline collector: suspend (T) -> Unit,
) = viewLifecycleOwner.lifecycleScope.launch { flow.collect(collector) } ) = launchWhenViewResumed { flow.collect(collector) }
fun Fragment.launchWhenViewResumed(
block: suspend CoroutineScope.() -> Unit,
) = viewLifecycleOwner.lifecycleScope.launchWhenResumed(block)

View File

@@ -4,5 +4,6 @@ import android.widget.ImageView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
interface ImageLoader { interface ImageLoader {
fun loadImage(url: String?, @DrawableRes placeholderId: Int, imageView: ImageView) fun loadImage(url: String?, @DrawableRes placeholderId: Int, imageView: ImageView)
} }

View File

@@ -0,0 +1,30 @@
package gq.kirmanak.mealient.ui.images
import android.widget.ImageView
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import dagger.hilt.android.scopes.FragmentScoped
import timber.log.Timber
import javax.inject.Inject
@FragmentScoped
class ImageLoaderGlide @Inject constructor(
private val fragment: Fragment,
) : ImageLoader {
private val requestManager: RequestManager
get() = Glide.with(fragment)
init {
Timber.v("init called with fragment = ${fragment.javaClass.simpleName}")
}
override fun loadImage(url: String?, placeholderId: Int, imageView: ImageView) {
Timber.v("loadImage() called with: url = $url, placeholderId = $placeholderId, imageView = $imageView")
requestManager.load(url)
.placeholder(placeholderId)
.centerCrop()
.into(imageView)
}
}

View File

@@ -1,25 +0,0 @@
package gq.kirmanak.mealient.ui.images
import android.widget.ImageView
import com.squareup.picasso.Picasso
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ImageLoaderPicasso @Inject constructor(
private val picasso: Picasso
) : ImageLoader {
override fun loadImage(url: String?, placeholderId: Int, imageView: ImageView) {
Timber.v("loadImage() called with: url = $url, placeholderId = $placeholderId, imageView = $imageView")
val width = imageView.measuredWidth
val height = imageView.measuredHeight
Timber.d("loadImage: width = $width, height = $height")
picasso.load(url).apply {
placeholder(placeholderId)
if (width > 0 && height > 0) resize(width, height).centerCrop()
into(imageView)
}
}
}

View File

@@ -1,34 +0,0 @@
package gq.kirmanak.mealient.ui.images
import android.content.Context
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import dagger.hilt.android.qualifiers.ApplicationContext
import gq.kirmanak.mealient.BuildConfig
import gq.kirmanak.mealient.di.AUTH_OK_HTTP
import okhttp3.OkHttpClient
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@Singleton
class PicassoBuilder @Inject constructor(
@ApplicationContext private val context: Context,
@Named(AUTH_OK_HTTP) private val okHttpClient: OkHttpClient
) {
fun buildPicasso(): Picasso {
Timber.v("buildPicasso() called")
val builder = Picasso.Builder(context)
builder.downloader(OkHttp3Downloader(okHttpClient))
if (BuildConfig.DEBUG_PICASSO) {
builder.loggingEnabled(true)
builder.indicatorsEnabled(true)
builder.listener { _, uri, exception ->
Timber.tag("Picasso").e(exception, "Can't load from $uri")
}
}
return builder.build()
}
}

View File

@@ -3,5 +3,6 @@ package gq.kirmanak.mealient.ui.recipes
import android.widget.ImageView import android.widget.ImageView
interface RecipeImageLoader { interface RecipeImageLoader {
suspend fun loadRecipeImage(view: ImageView, slug: String?)
fun loadRecipeImage(view: ImageView, slug: String?)
} }

View File

@@ -8,7 +8,7 @@ import timber.log.Timber
class RecipeViewHolder( class RecipeViewHolder(
private val binding: ViewHolderRecipeBinding, private val binding: ViewHolderRecipeBinding,
private val recipeViewModel: RecipeViewModel, private val recipeImageLoader: RecipeImageLoader,
private val clickListener: (RecipeSummaryEntity) -> Unit, private val clickListener: (RecipeSummaryEntity) -> Unit,
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
private val loadingPlaceholder by lazy { private val loadingPlaceholder by lazy {
@@ -18,7 +18,7 @@ class RecipeViewHolder(
fun bind(item: RecipeSummaryEntity?) { fun bind(item: RecipeSummaryEntity?) {
Timber.v("bind() called with: item = $item") Timber.v("bind() called with: item = $item")
binding.name.text = item?.name ?: loadingPlaceholder binding.name.text = item?.name ?: loadingPlaceholder
recipeViewModel.loadRecipeImage(binding.image, item) recipeImageLoader.loadRecipeImage(binding.image, item?.slug)
item?.let { entity -> item?.let { entity ->
binding.root.setOnClickListener { binding.root.setOnClickListener {
Timber.d("bind: item clicked $entity") Timber.d("bind: item clicked $entity")

View File

@@ -1,28 +1,15 @@
package gq.kirmanak.mealient.ui.recipes package gq.kirmanak.mealient.ui.recipes
import android.widget.ImageView
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn import androidx.paging.cachedIn
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealient.data.recipes.RecipeRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RecipeViewModel @Inject constructor( class RecipeViewModel @Inject constructor(recipeRepo: RecipeRepo) : ViewModel() {
recipeRepo: RecipeRepo,
private val recipeImageLoader: RecipeImageLoader
) : ViewModel() {
val pagingData = recipeRepo.createPager().flow.cachedIn(viewModelScope) val pagingData = recipeRepo.createPager().flow.cachedIn(viewModelScope)
fun loadRecipeImage(view: ImageView, recipeSummary: RecipeSummaryEntity?) {
Timber.v("loadRecipeImage() called with: view = $view, recipeSummary = $recipeSummary")
viewModelScope.launch {
recipeImageLoader.loadRecipeImage(view, recipeSummary?.slug)
}
}
} }

View File

@@ -11,10 +11,11 @@ import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealient.databinding.FragmentRecipesBinding import gq.kirmanak.mealient.databinding.FragmentRecipesBinding
import gq.kirmanak.mealient.extensions.collectWithViewLifecycle import gq.kirmanak.mealient.extensions.collectWhenViewResumed
import gq.kirmanak.mealient.extensions.refreshRequestFlow import gq.kirmanak.mealient.extensions.refreshRequestFlow
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class RecipesFragment : Fragment(R.layout.fragment_recipes) { class RecipesFragment : Fragment(R.layout.fragment_recipes) {
@@ -22,6 +23,9 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
private val viewModel by viewModels<RecipeViewModel>() private val viewModel by viewModels<RecipeViewModel>()
private val activityViewModel by activityViewModels<MainActivityViewModel>() private val activityViewModel by activityViewModels<MainActivityViewModel>()
@Inject
lateinit var recipeImageLoader: RecipeImageLoader
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState") Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState")
@@ -41,17 +45,17 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
private fun setupRecipeAdapter() { private fun setupRecipeAdapter() {
Timber.v("setupRecipeAdapter() called") Timber.v("setupRecipeAdapter() called")
val adapter = RecipesPagingAdapter(viewModel, ::navigateToRecipeInfo) val adapter = RecipesPagingAdapter(recipeImageLoader, ::navigateToRecipeInfo)
binding.recipes.adapter = adapter binding.recipes.adapter = adapter
collectWithViewLifecycle(viewModel.pagingData) { collectWhenViewResumed(viewModel.pagingData) {
Timber.v("setupRecipeAdapter: received data update") Timber.v("setupRecipeAdapter: received data update")
adapter.submitData(lifecycle, it) adapter.submitData(lifecycle, it)
} }
collectWithViewLifecycle(adapter.onPagesUpdatedFlow) { collectWhenViewResumed(adapter.onPagesUpdatedFlow) {
Timber.v("setupRecipeAdapter: pages updated") Timber.v("setupRecipeAdapter: pages updated")
binding.refresher.isRefreshing = false binding.refresher.isRefreshing = false
} }
collectWithViewLifecycle(binding.refresher.refreshRequestFlow()) { collectWhenViewResumed(binding.refresher.refreshRequestFlow()) {
Timber.v("setupRecipeAdapter: received refresh request") Timber.v("setupRecipeAdapter: received refresh request")
adapter.refresh() adapter.refresh()
} }

View File

@@ -9,7 +9,7 @@ import gq.kirmanak.mealient.databinding.ViewHolderRecipeBinding
import timber.log.Timber import timber.log.Timber
class RecipesPagingAdapter( class RecipesPagingAdapter(
private val viewModel: RecipeViewModel, private val recipeImageLoader: RecipeImageLoader,
private val clickListener: (RecipeSummaryEntity) -> Unit private val clickListener: (RecipeSummaryEntity) -> Unit
) : PagingDataAdapter<RecipeSummaryEntity, RecipeViewHolder>(RecipeDiffCallback) { ) : PagingDataAdapter<RecipeSummaryEntity, RecipeViewHolder>(RecipeDiffCallback) {
override fun onBindViewHolder(holder: RecipeViewHolder, position: Int) { override fun onBindViewHolder(holder: RecipeViewHolder, position: Int) {
@@ -21,7 +21,7 @@ class RecipesPagingAdapter(
Timber.v("onCreateViewHolder() called with: parent = $parent, viewType = $viewType") Timber.v("onCreateViewHolder() called with: parent = $parent, viewType = $viewType")
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
val binding = ViewHolderRecipeBinding.inflate(inflater, parent, false) val binding = ViewHolderRecipeBinding.inflate(inflater, parent, false)
return RecipeViewHolder(binding, viewModel, clickListener) return RecipeViewHolder(binding, recipeImageLoader, clickListener)
} }
private object RecipeDiffCallback : DiffUtil.ItemCallback<RecipeSummaryEntity>() { private object RecipeDiffCallback : DiffUtil.ItemCallback<RecipeSummaryEntity>() {

View File

@@ -14,7 +14,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.databinding.FragmentRecipeInfoBinding import gq.kirmanak.mealient.databinding.FragmentRecipeInfoBinding
import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class RecipeInfoFragment : BottomSheetDialogFragment() { class RecipeInfoFragment : BottomSheetDialogFragment() {
@@ -25,6 +27,9 @@ class RecipeInfoFragment : BottomSheetDialogFragment() {
private val ingredientsAdapter = RecipeIngredientsAdapter() private val ingredientsAdapter = RecipeIngredientsAdapter()
private val instructionsAdapter = RecipeInstructionsAdapter() private val instructionsAdapter = RecipeInstructionsAdapter()
@Inject
lateinit var recipeImageLoader: RecipeImageLoader
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@@ -41,10 +46,10 @@ class RecipeInfoFragment : BottomSheetDialogFragment() {
with(binding) { with(binding) {
ingredientsList.adapter = ingredientsAdapter ingredientsList.adapter = ingredientsAdapter
instructionsList.adapter = instructionsAdapter instructionsList.adapter = instructionsAdapter
recipeImageLoader.loadRecipeImage(image, arguments.recipeSlug)
} }
with(viewModel) { with(viewModel) {
loadRecipeImage(binding.image, arguments.recipeSlug)
loadRecipeInfo(arguments.recipeId, arguments.recipeSlug) loadRecipeInfo(arguments.recipeId, arguments.recipeSlug)
uiState.observe(viewLifecycleOwner, ::onUiStateChange) uiState.observe(viewLifecycleOwner, ::onUiStateChange)
} }

View File

@@ -1,6 +1,5 @@
package gq.kirmanak.mealient.ui.recipes.info package gq.kirmanak.mealient.ui.recipes.info
import android.widget.ImageView
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -8,7 +7,6 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealient.data.recipes.RecipeRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.extensions.runCatchingExceptCancel import gq.kirmanak.mealient.extensions.runCatchingExceptCancel
import gq.kirmanak.mealient.ui.recipes.RecipeImageLoader
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@@ -16,17 +14,11 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RecipeInfoViewModel @Inject constructor( class RecipeInfoViewModel @Inject constructor(
private val recipeRepo: RecipeRepo, private val recipeRepo: RecipeRepo,
private val recipeImageLoader: RecipeImageLoader,
) : ViewModel() { ) : ViewModel() {
private val _uiState = MutableLiveData(RecipeInfoUiState()) private val _uiState = MutableLiveData(RecipeInfoUiState())
val uiState: LiveData<RecipeInfoUiState> get() = _uiState val uiState: LiveData<RecipeInfoUiState> get() = _uiState
fun loadRecipeImage(view: ImageView, recipeSlug: String) {
Timber.v("loadRecipeImage() called with: view = $view, recipeSlug = $recipeSlug")
viewModelScope.launch { recipeImageLoader.loadRecipeImage(view, recipeSlug) }
}
fun loadRecipeInfo(recipeId: Long, recipeSlug: String) { fun loadRecipeInfo(recipeId: Long, recipeSlug: String) {
Timber.v("loadRecipeInfo() called with: recipeId = $recipeId, recipeSlug = $recipeSlug") Timber.v("loadRecipeInfo() called with: recipeId = $recipeId, recipeSlug = $recipeSlug")
_uiState.value = RecipeInfoUiState() _uiState.value = RecipeInfoUiState()

View File

@@ -1,5 +1,6 @@
package gq.kirmanak.mealient.data.recipes.impl package gq.kirmanak.mealient.data.recipes.impl
import androidx.fragment.app.Fragment
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import gq.kirmanak.mealient.data.baseurl.BaseURLStorage import gq.kirmanak.mealient.data.baseurl.BaseURLStorage
import gq.kirmanak.mealient.ui.images.ImageLoader import gq.kirmanak.mealient.ui.images.ImageLoader
@@ -21,10 +22,13 @@ class RecipeImageLoaderImplTest {
@MockK @MockK
lateinit var imageLoader: ImageLoader lateinit var imageLoader: ImageLoader
@MockK
lateinit var fragment: Fragment
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
subject = RecipeImageLoaderImpl(imageLoader, baseURLStorage) subject = RecipeImageLoaderImpl(imageLoader, baseURLStorage, fragment)
prepareBaseURL("https://google.com/") prepareBaseURL("https://google.com/")
} }