From b4a01d7753b5c15d9fd6a4a66326dff1fc468216 Mon Sep 17 00:00:00 2001 From: Serchinastico <54cymru@gmail.com> Date: Wed, 30 Jan 2019 17:49:41 +0100 Subject: [PATCH] Add LayoutContainer for SuperHeroViewHolder Add binding adapter to load images Add data binding to recycler view adapter Fix tests --- .../ui/view/SuperHeroViewHolderTest.kt | 51 +++++++---- .../superheroes/common/BindingAdapters.kt | 12 +++ .../ui/view/EditSuperHeroActivity.kt | 2 - .../ui/view/SuperHeroDetailActivity.kt | 2 - .../ui/view/adapter/SuperHeroViewHolder.kt | 30 +------ .../ui/view/adapter/SuperHeroesAdapter.kt | 11 ++- .../res/layout/edit_super_hero_activity.xml | 1 + .../res/layout/super_hero_detail_activity.xml | 1 + app/src/main/res/layout/super_hero_row.xml | 87 +++++++++++-------- 9 files changed, 112 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/com/karumi/jetpack/superheroes/common/BindingAdapters.kt diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt index 8204503..382c612 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroViewHolderTest.kt @@ -1,8 +1,10 @@ package com.karumi.jetpack.superheroes.ui.view import android.view.LayoutInflater +import androidx.databinding.DataBindingUtil import androidx.test.platform.app.InstrumentationRegistry import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.databinding.SuperHeroRowBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesPresenter import com.karumi.jetpack.superheroes.ui.view.adapter.SuperHeroViewHolder @@ -14,9 +16,9 @@ class SuperHeroViewHolderTest : ScreenshotTest { @Test fun showsAnySuperHero() { val superHero = givenASuperHero() - val holder = givenASuperHeroViewHolder() + val (holder, binding) = givenASuperHeroViewHolder() - holder.render(superHero) + renderViewHolder(superHero, holder, binding) compareScreenshot(holder, R.dimen.super_hero_row_height) } @@ -24,9 +26,9 @@ class SuperHeroViewHolderTest : ScreenshotTest { @Test fun showsSuperHeroesWithLongNames() { val superHero = givenASuperHeroWithALongName() - val holder = givenASuperHeroViewHolder() + val (holder, binding) = givenASuperHeroViewHolder() - holder.render(superHero) + renderViewHolder(superHero, holder, binding) compareScreenshot(holder, R.dimen.super_hero_row_height) } @@ -34,9 +36,9 @@ class SuperHeroViewHolderTest : ScreenshotTest { @Test fun showsSuperHeroesWithLongDescriptions() { val superHero = givenASuperHeroWithALongDescription() - val holder = givenASuperHeroViewHolder() + val (holder, binding) = givenASuperHeroViewHolder() - holder.render(superHero) + renderViewHolder(superHero, holder, binding) compareScreenshot(holder, R.dimen.super_hero_row_height) } @@ -44,23 +46,34 @@ class SuperHeroViewHolderTest : ScreenshotTest { @Test fun showsAvengersBadge() { val superHero = givenASuperHero(isAvenger = true) - val holder = givenASuperHeroViewHolder() + val (holder, binding) = givenASuperHeroViewHolder() - holder.render(superHero) + renderViewHolder(superHero, holder, binding) compareScreenshot(holder, R.dimen.super_hero_row_height) } - private fun givenASuperHeroViewHolder(): SuperHeroViewHolder { - val context = InstrumentationRegistry.getInstrumentation().targetContext - val inflater = LayoutInflater.from(context) - val view = inflater.inflate(R.layout.super_hero_row, null, false) - return SuperHeroViewHolder( - view, - mock(SuperHeroesPresenter::class.java) - ) + private fun renderViewHolder( + superHero: SuperHero, + holder: SuperHeroViewHolder, + binding: SuperHeroRowBinding + ) { + holder.render(superHero) + binding.executePendingBindings() } + private fun givenASuperHeroViewHolder(): Pair = + runOnUi { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val inflater = LayoutInflater.from(context) + val binding: SuperHeroRowBinding = + DataBindingUtil.inflate(inflater, R.layout.super_hero_row, null, false) + SuperHeroViewHolder( + binding, + mock(SuperHeroesPresenter::class.java) + ) to binding + } + private fun givenASuperHeroWithALongDescription(): SuperHero { val superHeroName = "Super Hero Name" val superHeroDescription = """ @@ -94,4 +107,10 @@ class SuperHeroViewHolderTest : ScreenshotTest { superHeroDescription: String = "Super Hero Description", isAvenger: Boolean = false ): SuperHero = SuperHero(superHeroId, superHeroName, null, isAvenger, superHeroDescription) +} + +private fun runOnUi(block: () -> T): T { + var response: T? = null + InstrumentationRegistry.getInstrumentation().runOnMainSync { response = block() } + return response!! } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/common/BindingAdapters.kt b/app/src/main/java/com/karumi/jetpack/superheroes/common/BindingAdapters.kt new file mode 100644 index 0000000..3a78ab6 --- /dev/null +++ b/app/src/main/java/com/karumi/jetpack/superheroes/common/BindingAdapters.kt @@ -0,0 +1,12 @@ +package com.karumi.jetpack.superheroes.common + +import android.widget.ImageView +import androidx.databinding.BindingAdapter +import com.karumi.jetpack.superheroes.ui.utils.picasso + +@BindingAdapter("imageUrl") +fun setImageUrl(view: ImageView, url: String?) { + if (url != null) { + view.context.picasso.load(url).fit().centerCrop().fit().into(view) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt index d4efc5c..d854bb7 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt @@ -10,7 +10,6 @@ import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById import com.karumi.jetpack.superheroes.domain.usecase.SaveSuperHero import com.karumi.jetpack.superheroes.ui.presenter.EditSuperHeroPresenter -import com.karumi.jetpack.superheroes.ui.utils.setImageBackground import kotlinx.android.synthetic.main.edit_super_hero_activity.* import org.kodein.di.Kodein import org.kodein.di.erased.bind @@ -73,7 +72,6 @@ class EditSuperHeroActivity : override fun showSuperHero(superHero: SuperHero) { binding.superHero = superHero - iv_super_hero_photo.setImageBackground(superHero.photo) } override val activityModules = diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt index e48c670..0555888 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt @@ -8,7 +8,6 @@ import com.karumi.jetpack.superheroes.databinding.SuperHeroDetailActivityBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroDetailPresenter -import com.karumi.jetpack.superheroes.ui.utils.setImageBackground import kotlinx.android.synthetic.main.super_hero_detail_activity.* import org.kodein.di.Kodein import org.kodein.di.erased.bind @@ -58,7 +57,6 @@ class SuperHeroDetailActivity : override fun showSuperHero(superHero: SuperHero) { title = superHero.name binding.superHero = superHero - iv_super_hero_photo.setImageBackground(superHero.photo) } override fun openEditSuperHero(superHeroId: String) { diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroViewHolder.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroViewHolder.kt index 04ef259..543e7b6 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroViewHolder.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroViewHolder.kt @@ -1,43 +1,21 @@ package com.karumi.jetpack.superheroes.ui.view.adapter -import android.view.View -import android.widget.ImageView -import android.widget.TextView import androidx.recyclerview.widget.RecyclerView -import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.databinding.SuperHeroRowBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesPresenter -import com.karumi.jetpack.superheroes.ui.utils.setImageBackground class SuperHeroViewHolder( - itemView: View, + private val binding: SuperHeroRowBinding, private val presenter: SuperHeroesPresenter -) : RecyclerView.ViewHolder(itemView) { - - private val photoImageView: ImageView = itemView.findViewById(R.id.iv_super_hero_photo) - private val nameTextView: TextView = itemView.findViewById(R.id.tv_super_hero_name) - private val avengersBadgeView: View = itemView.findViewById(R.id.iv_avengers_badge) +) : RecyclerView.ViewHolder(binding.root) { fun render(superHero: SuperHero) { hookListeners(superHero) - renderSuperHeroPhoto(superHero.photo) - renderSuperHeroName(superHero.name) - renderAvengersBadge(superHero.isAvenger) + binding.superHero = superHero } private fun hookListeners(superHero: SuperHero) { itemView.setOnClickListener { presenter.onSuperHeroClicked(superHero) } } - - private fun renderSuperHeroPhoto(photo: String?) { - photoImageView.setImageBackground(photo) - } - - private fun renderSuperHeroName(name: String) { - nameTextView.text = name - } - - private fun renderAvengersBadge(isAvenger: Boolean) { - avengersBadgeView.visibility = if (isAvenger) View.VISIBLE else View.GONE - } } \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroesAdapter.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroesAdapter.kt index a3988b4..4124a53 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroesAdapter.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/adapter/SuperHeroesAdapter.kt @@ -2,8 +2,10 @@ package com.karumi.jetpack.superheroes.ui.view.adapter import android.view.LayoutInflater import android.view.ViewGroup +import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.databinding.SuperHeroRowBinding import com.karumi.jetpack.superheroes.domain.model.SuperHero import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesPresenter @@ -17,11 +19,14 @@ internal class SuperHeroesAdapter( } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SuperHeroViewHolder { - val view = LayoutInflater.from(parent.context).inflate( - R.layout.super_hero_row, parent, + val binding: SuperHeroRowBinding = DataBindingUtil.inflate( + LayoutInflater.from(parent.context), + R.layout.super_hero_row, + parent, false ) - return SuperHeroViewHolder(view, presenter) + + return SuperHeroViewHolder(binding, presenter) } override fun onBindViewHolder(holder: SuperHeroViewHolder, position: Int) { diff --git a/app/src/main/res/layout/edit_super_hero_activity.xml b/app/src/main/res/layout/edit_super_hero_activity.xml index b73e69f..2b0efa2 100644 --- a/app/src/main/res/layout/edit_super_hero_activity.xml +++ b/app/src/main/res/layout/edit_super_hero_activity.xml @@ -46,6 +46,7 @@ android:id="@+id/iv_super_hero_photo" android:layout_width="match_parent" android:layout_height="@dimen/super_hero_detail_header_height" + app:imageUrl="@{ superHero.photo }" app:layout_constraintTop_toTopOf="parent" tools:background="@color/color_primary_dark" tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/layout/super_hero_detail_activity.xml b/app/src/main/res/layout/super_hero_detail_activity.xml index 1dbffa8..256e817 100644 --- a/app/src/main/res/layout/super_hero_detail_activity.xml +++ b/app/src/main/res/layout/super_hero_detail_activity.xml @@ -43,6 +43,7 @@ android:id="@+id/iv_super_hero_photo" android:layout_width="match_parent" android:layout_height="@dimen/super_hero_detail_header_height" + app:imageUrl="@{ superHero.photo }" app:layout_constraintTop_toBottomOf="@id/toolbar" tools:background="@color/color_primary_dark" tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/layout/super_hero_row.xml b/app/src/main/res/layout/super_hero_row.xml index 9e2399d..e670ce9 100644 --- a/app/src/main/res/layout/super_hero_row.xml +++ b/app/src/main/res/layout/super_hero_row.xml @@ -1,41 +1,56 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + - + + + - - - - - - \ No newline at end of file + android:layout_height="@dimen/super_hero_row_height"> + + + + + + + + + + +