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

03b-advanced-data-binding #10

Open
wants to merge 1 commit into
base: 03a-data-binding
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -51,15 +53,17 @@ class SuperHeroViewHolderTest : ScreenshotTest {
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>(SuperHeroesPresenter::class.java)
)
}
private fun givenASuperHeroViewHolder(): SuperHeroViewHolder =
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>(SuperHeroesPresenter::class.java)
)
}

private fun givenASuperHeroWithALongDescription(): SuperHero {
val superHeroName = "Super Hero Name"
Expand Down Expand Up @@ -94,4 +98,10 @@ class SuperHeroViewHolderTest : ScreenshotTest {
superHeroDescription: String = "Super Hero Description",
isAvenger: Boolean = false
): SuperHero = SuperHero(superHeroId, superHeroName, null, isAvenger, superHeroDescription)
}

private fun <T> runOnUi(block: () -> T): T {
var response: T? = null
InstrumentationRegistry.getInstrumentation().runOnMainSync { response = block() }
return response!!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.karumi.jetpack.superheroes.common

import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.squareup.picasso.Picasso

@BindingAdapter("imageUrl")
fun setImageUrl(view: ImageView, url: String?) {
if (url != null) {
Picasso.get().load(url).fit().centerCrop().fit().into(view)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,21 @@ class EditSuperHeroPresenter(
}

override fun onSaveSuperHeroSelected(
name: String,
description: String,
isAvenger: Boolean
editableSuperHero: EditSuperHeroPresenter.EditableSuperHero
) {
saveSuperHero(name, description, isAvenger)
saveSuperHero(editableSuperHero)
}

private fun saveSuperHero(
name: String,
description: String,
isAvenger: Boolean
editableSuperHero: EditSuperHeroPresenter.EditableSuperHero
) = executor.submit {
view?.showLoading()
val superHero = superHero ?: return@submit
saveSuperHero(
superHero.copy(
name = name,
description = description,
isAvenger = isAvenger
name = editableSuperHero.name,
description = editableSuperHero.description,
isAvenger = editableSuperHero.isAvenger
)
)
view?.close()
Expand All @@ -68,6 +64,12 @@ class EditSuperHeroPresenter(
[email protected] = superHero
}

data class EditableSuperHero(
var isAvenger: Boolean,
var name: String,
var description: String
)

interface View {
fun close()
fun hideLoading()
Expand All @@ -77,9 +79,5 @@ class EditSuperHeroPresenter(
}

interface EditSuperHeroListener {
fun onSaveSuperHeroSelected(
name: String,
description: String,
isAvenger: Boolean
)
fun onSaveSuperHeroSelected(editableSuperHero: EditSuperHeroPresenter.EditableSuperHero)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class SuperHeroesPresenter(
view: View,
private val getSuperHeroes: GetSuperHeroes,
private val executor: ExecutorService
) : LifecycleObserver {
) : SuperHeroesListener, LifecycleObserver {

private val view: View? by weak(view)

Expand All @@ -37,7 +37,7 @@ class SuperHeroesPresenter(
}
}

fun onSuperHeroClicked(superHero: SuperHero) {
override fun onSuperHeroClicked(superHero: SuperHero) {
view?.openDetail(superHero.id)
}

Expand All @@ -48,4 +48,8 @@ class SuperHeroesPresenter(
fun showSuperHeroes(superHeroes: List<SuperHero>)
fun openDetail(id: String)
}
}

interface SuperHeroesListener {
fun onSuperHeroClicked(superHero: SuperHero)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.karumi.jetpack.superheroes.ui.view

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.widget.Toolbar
import com.karumi.jetpack.superheroes.R
import com.karumi.jetpack.superheroes.common.module
Expand All @@ -11,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.erased.bind
import org.kodein.di.erased.instance
Expand All @@ -37,17 +35,6 @@ class EditSuperHeroActivity :
get() = toolbar
private val superHeroId: String by lazy { intent?.extras?.getString(SUPER_HERO_ID_KEY) ?: "" }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bt_save_edition.setOnClickListener {
presenter.onSaveSuperHeroSelected(
name = et_super_hero_name.text?.toString() ?: "",
description = et_super_hero_description.text?.toString() ?: "",
isAvenger = cb_is_avenger.isChecked
)
}
}

override fun configureBinding(binding: EditSuperHeroActivityBinding) {
binding.listener = presenter
binding.isLoading = false
Expand All @@ -71,8 +58,9 @@ class EditSuperHeroActivity :
}

override fun showSuperHero(superHero: SuperHero) = runOnUiThread {
binding.listener = presenter
binding.superHero = superHero
iv_super_hero_photo.setImageBackground(superHero.photo)
binding.editableSuperHero = superHero.toEditable()
}

override val activityModules = module {
Expand All @@ -82,4 +70,7 @@ class EditSuperHeroActivity :
bind<GetSuperHeroById>() with provider { GetSuperHeroById(instance()) }
bind<SaveSuperHero>() with provider { SaveSuperHero(instance()) }
}

private fun SuperHero.toEditable() =
EditSuperHeroPresenter.EditableSuperHero(isAvenger, name, description)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,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.erased.bind
import org.kodein.di.erased.instance
Expand Down Expand Up @@ -55,7 +54,6 @@ class SuperHeroDetailActivity :
override fun showSuperHero(superHero: SuperHero) = runOnUiThread {
title = superHero.name
binding.superHero = superHero
iv_super_hero_photo.setImageBackground(superHero.photo)
}

override fun openEditSuperHero(superHeroId: String) = runOnUiThread {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,18 @@
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
import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesListener

class SuperHeroViewHolder(
itemView: View,
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)
private val binding: SuperHeroRowBinding,
private val listener: SuperHeroesListener
) : RecyclerView.ViewHolder(binding.root) {

fun render(superHero: SuperHero) {
hookListeners(superHero)
renderSuperHeroPhoto(superHero.photo)
renderSuperHeroName(superHero.name)
renderAvengersBadge(superHero.isAvenger)
}

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
binding.superHero = superHero
binding.listener = listener
binding.executePendingBindings()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ 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
import com.karumi.jetpack.superheroes.ui.presenter.SuperHeroesListener

internal class SuperHeroesAdapter(
private val presenter: SuperHeroesPresenter
private val listener: SuperHeroesListener
) : RecyclerView.Adapter<SuperHeroViewHolder>() {
private val superHeroes: MutableList<SuperHero> = ArrayList()

Expand All @@ -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, listener)
}

override fun onBindViewHolder(holder: SuperHeroViewHolder, position: Int) {
Expand Down
12 changes: 9 additions & 3 deletions app/src/main/res/layout/edit_super_hero_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
name="superHero"
type="com.karumi.jetpack.superheroes.domain.model.SuperHero" />

<variable
name="editableSuperHero"
type="com.karumi.jetpack.superheroes.ui.presenter.EditSuperHeroPresenter.EditableSuperHero" />

<variable
name="isLoading"
type="boolean" />
Expand Down Expand Up @@ -46,6 +50,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" />
Expand All @@ -68,7 +73,7 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:buttonTint="@color/white"
android:checked="@{ superHero.avenger }"
android:checked="@={ editableSuperHero.avenger, default = false }"
android:enabled="@{ superHero != null }"
android:text="@string/is_super_hero_an_avenger_checkbox"
android:textColor="@color/white"
Expand All @@ -92,7 +97,7 @@
android:hint="@string/edit_super_hero_name_hint"
android:importantForAutofill="no"
android:inputType="text"
android:text="@{ superHero.name }"
android:text="@={ editableSuperHero.name }"
android:textColor="@color/white"
tools:ignore="UnusedAttribute" />

Expand All @@ -116,7 +121,7 @@
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:scrollbars="vertical"
android:text="@{ superHero.description }"
android:text="@={ editableSuperHero.description }"
android:textColor="@color/white"
tools:ignore="UnusedAttribute" />

Expand Down Expand Up @@ -150,6 +155,7 @@
android:layout_height="56dp"
android:background="@color/royal_blue"
android:enabled="@{ superHero != null }"
android:onClick="@{ () -> listener.onSaveSuperHeroSelected(editableSuperHero) }"
android:text="@string/save_edited_super_hero_button"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/super_hero_detail_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
Loading