Skip to content

Commit 91044de

Browse files
add PropertyListAdapter and bind properties
1 parent 98f4e62 commit 91044de

9 files changed

Lines changed: 374 additions & 8 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.smarttoolfactory.home.adapter
2+
3+
import android.widget.ImageButton
4+
import androidx.annotation.LayoutRes
5+
import androidx.databinding.ViewDataBinding
6+
import androidx.recyclerview.widget.DiffUtil
7+
import androidx.recyclerview.widget.RecyclerView
8+
import com.smarttoolfactory.core.ui.adapter.BaseListAdapter
9+
import com.smarttoolfactory.domain.model.PropertyItem
10+
import com.smarttoolfactory.home.BR
11+
import com.smarttoolfactory.home.R
12+
import com.smarttoolfactory.home.databinding.RowPropertyBinding
13+
14+
class PropertyItemListAdapter(
15+
@LayoutRes private val layoutId: Int,
16+
private val onItemClicked: ((PropertyItem) -> Unit)? = null,
17+
private val onLikeButtonClicked: ((PropertyItem) -> Unit)? = null
18+
) :
19+
BaseListAdapter<PropertyItem>(
20+
layoutId,
21+
PropertyItemDiffCallback()
22+
) {
23+
24+
override fun onViewHolderBound(
25+
binding: ViewDataBinding,
26+
item: PropertyItem,
27+
position: Int,
28+
payloads: MutableList<Any>
29+
) {
30+
binding.setVariable(BR.item, item)
31+
}
32+
33+
/**
34+
* Add click listener here to prevent setting listener after a ViewHolder every time
35+
* ViewHolder is scrolled and onBindViewHolder is called
36+
*/
37+
override fun onViewHolderCreated(
38+
viewHolder: RecyclerView.ViewHolder,
39+
viewType: Int,
40+
binding: ViewDataBinding
41+
) {
42+
43+
binding.root.setOnClickListener {
44+
onItemClicked?.let {
45+
it((getItem(viewHolder.bindingAdapterPosition)))
46+
}
47+
}
48+
49+
if (binding is RowPropertyBinding) {
50+
51+
binding.ivLike.setOnClickListener { likeButton ->
52+
onLikeButtonClicked?.let { onLikeButtonClick ->
53+
54+
getItem(viewHolder.bindingAdapterPosition).apply {
55+
// Change like status of PropertyItem
56+
isFavorite = !isFavorite
57+
onLikeButtonClick(this)
58+
59+
// Set image source of like button
60+
val imageResource = if (isFavorite) {
61+
R.drawable.ic_baseline_favorite_24
62+
} else {
63+
R.drawable.ic_baseline_favorite_border_24
64+
}
65+
(likeButton as? ImageButton)?.setImageResource(imageResource)
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}
72+
73+
/**
74+
* Callback for calculating the diff between two non-null items in a list.
75+
*
76+
* Used by ListAdapter to calculate the minimum number of changes between and old list and a new
77+
* list that's been passed to `submitList`.
78+
*/
79+
class PropertyItemDiffCallback : DiffUtil.ItemCallback<PropertyItem>() {
80+
81+
override fun areItemsTheSame(
82+
oldItem: PropertyItem,
83+
newItem: PropertyItem
84+
): Boolean {
85+
return oldItem == newItem
86+
}
87+
88+
override fun areContentsTheSame(
89+
oldItem: PropertyItem,
90+
newItem: PropertyItem
91+
): Boolean {
92+
return oldItem.id == newItem.id
93+
}
94+
}

features/home/src/main/java/com/smarttoolfactory/home/propertylist/PropertyListFlowFragment.kt

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.smarttoolfactory.home.propertylist
22

33
import android.os.Bundle
4+
import androidx.core.os.bundleOf
5+
import androidx.recyclerview.widget.LinearLayoutManager
46
import com.smarttoolfactory.core.di.CoreModuleDependencies
57
import com.smarttoolfactory.core.ui.fragment.DynamicNavigationFragment
68
import com.smarttoolfactory.home.R
9+
import com.smarttoolfactory.home.adapter.PropertyItemListAdapter
710
import com.smarttoolfactory.home.databinding.FragmentPropertyListBinding
811
import com.smarttoolfactory.home.di.DaggerHomeComponent
912
import com.smarttoolfactory.home.viewmodel.PropertyListViewModelFlow
@@ -24,7 +27,40 @@ class PropertyListFlowFragment : DynamicNavigationFragment<FragmentPropertyListB
2427
}
2528

2629
override fun bindViews() {
27-
super.bindViews()
30+
dataBinding.viewModel = viewModel
31+
32+
dataBinding.recyclerView.apply {
33+
34+
// Set Layout manager
35+
this.layoutManager =
36+
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
37+
38+
// Set RecyclerViewAdapter
39+
this.adapter =
40+
PropertyItemListAdapter(R.layout.row_property, viewModel::onClick)
41+
}
42+
43+
val swipeRefreshLayout = dataBinding.swipeRefreshLayout
44+
45+
swipeRefreshLayout.setOnRefreshListener {
46+
swipeRefreshLayout.isRefreshing = false
47+
viewModel.refreshPropertyList()
48+
}
49+
50+
subscribeGoToDetailScreen()
51+
}
52+
53+
private fun subscribeGoToDetailScreen() {
54+
55+
viewModel.goToDetailScreen.observe(
56+
viewLifecycleOwner,
57+
{
58+
59+
it.getContentIfNotHandled()?.let { propertyItem ->
60+
val bundle = bundleOf("property" to propertyItem)
61+
}
62+
}
63+
)
2864
}
2965

3066
private fun initCoreDependentInjection() {

features/home/src/main/java/com/smarttoolfactory/home/propertylist/PropertyListRxjava3Fragment.kt

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.smarttoolfactory.home.propertylist
22

33
import android.os.Bundle
4+
import androidx.core.os.bundleOf
5+
import androidx.recyclerview.widget.LinearLayoutManager
46
import com.smarttoolfactory.core.di.CoreModuleDependencies
57
import com.smarttoolfactory.core.ui.fragment.DynamicNavigationFragment
68
import com.smarttoolfactory.home.R
9+
import com.smarttoolfactory.home.adapter.PropertyItemListAdapter
710
import com.smarttoolfactory.home.databinding.FragmentPropertyListBinding
811
import com.smarttoolfactory.home.di.DaggerHomeComponent
912
import com.smarttoolfactory.home.viewmodel.PropertyListViewModelRxJava3
@@ -24,7 +27,40 @@ class PropertyListRxjava3Fragment : DynamicNavigationFragment<FragmentPropertyLi
2427
}
2528

2629
override fun bindViews() {
27-
super.bindViews()
30+
dataBinding.viewModel = viewModel
31+
32+
dataBinding.recyclerView.apply {
33+
34+
// Set Layout manager
35+
this.layoutManager =
36+
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
37+
38+
// Set RecyclerViewAdapter
39+
this.adapter =
40+
PropertyItemListAdapter(R.layout.row_property, viewModel::onClick)
41+
}
42+
43+
val swipeRefreshLayout = dataBinding.swipeRefreshLayout
44+
45+
swipeRefreshLayout.setOnRefreshListener {
46+
swipeRefreshLayout.isRefreshing = false
47+
viewModel.refreshPropertyList()
48+
}
49+
50+
subscribeGoToDetailScreen()
51+
}
52+
53+
private fun subscribeGoToDetailScreen() {
54+
55+
viewModel.goToDetailScreen.observe(
56+
viewLifecycleOwner,
57+
{
58+
59+
it.getContentIfNotHandled()?.let { propertyItem ->
60+
val bundle = bundleOf("property" to propertyItem)
61+
}
62+
}
63+
)
2864
}
2965

3066
private fun initCoreDependentInjection() {

features/home/src/main/java/com/smarttoolfactory/home/viewbindings/ViewBindings.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ fun View.visibilityBasedOn(condition: Boolean) {
6565
fun ImageButton.setFavoriteImageSrc(favorite: Boolean) {
6666

6767
val imageResource = if (favorite) R.drawable.ic_baseline_favorite_24
68-
else R.drawable.ic_baseline_favorite_24
68+
else R.drawable.ic_baseline_favorite_border_24
6969

7070
setImageResource(imageResource)
7171
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M6.36,18.78L6.61,21l1.62,-1.54l2.77,-7.6c-0.68,-0.17 -1.28,-0.51 -1.77,-0.98L6.36,18.78z"/>
10+
<path
11+
android:fillColor="@android:color/white"
12+
android:pathData="M14.77,10.88c-0.49,0.47 -1.1,0.81 -1.77,0.98l2.77,7.6L17.39,21l0.26,-2.22L14.77,10.88z"/>
13+
<path
14+
android:fillColor="@android:color/white"
15+
android:pathData="M15,8c0,-1.3 -0.84,-2.4 -2,-2.82V3h-2v2.18C9.84,5.6 9,6.7 9,8c0,1.66 1.34,3 3,3S15,9.66 15,8zM12,9c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C13,8.55 12.55,9 12,9z"/>
16+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M7,14c1.66,0 3,-1.34 3,-3S8.66,8 7,8s-3,1.34 -3,3 1.34,3 3,3zM7,10c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,7h-8v8L3,15L3,7L1,7v10h22v-6c0,-2.21 -1.79,-4 -4,-4zM21,15h-8L13,9h6c1.1,0 2,0.9 2,2v4z"/>
10+
</vector>
Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,60 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<layout>
32

4-
<androidx.constraintlayout.widget.ConstraintLayout
5-
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
3+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:app="http://schemas.android.com/apk/res-auto">
5+
6+
<data>
7+
8+
<import type="android.view.View" />
9+
10+
<variable
11+
name="viewModel"
12+
type="com.smarttoolfactory.home.viewmodel.AbstractPropertyListVM" />
13+
</data>
14+
15+
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
16+
android:id="@+id/swipeRefreshLayout"
17+
android:layout_width="match_parent"
618
android:layout_height="match_parent">
719

8-
</androidx.constraintlayout.widget.ConstraintLayout>
20+
<androidx.constraintlayout.widget.ConstraintLayout
21+
android:layout_width="match_parent"
22+
android:layout_height="match_parent">
23+
24+
<androidx.recyclerview.widget.RecyclerView
25+
android:id="@+id/recycler_view"
26+
visibilityBasedOn="@{viewModel.propertyListViewState.success}"
27+
android:layout_width="match_parent"
28+
android:layout_height="match_parent"
29+
android:paddingTop="16dp"
30+
app:items="@{viewModel.propertyListViewState.data}"
31+
app:layout_constraintBottom_toBottomOf="parent"
32+
app:layout_constraintEnd_toEndOf="parent"
33+
app:layout_constraintStart_toStartOf="parent"
34+
app:layout_constraintTop_toTopOf="parent" />
35+
36+
37+
<androidx.appcompat.widget.AppCompatTextView
38+
android:id="@+id/tv_error"
39+
visibilityBasedOn="@{viewModel.propertyListViewState.shouldShowErrorMessage()}"
40+
android:layout_width="wrap_content"
41+
android:layout_height="wrap_content"
42+
android:text="@{`⚠️ ` + viewModel.propertyListViewState.errorMessage}"
43+
app:layout_constraintBottom_toBottomOf="parent"
44+
app:layout_constraintEnd_toEndOf="parent"
45+
app:layout_constraintStart_toStartOf="parent"
46+
app:layout_constraintTop_toTopOf="@+id/recycler_view" />
47+
48+
<ProgressBar
49+
android:id="@+id/progress_bar"
50+
visibilityBasedOn="@{viewModel.propertyListViewState.loading}"
51+
android:layout_width="wrap_content"
52+
android:layout_height="wrap_content"
53+
app:layout_constraintBottom_toBottomOf="parent"
54+
app:layout_constraintEnd_toEndOf="parent"
55+
app:layout_constraintStart_toStartOf="parent"
56+
app:layout_constraintTop_toTopOf="@+id/recycler_view" />
57+
</androidx.constraintlayout.widget.ConstraintLayout>
58+
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
959

1060
</layout>

0 commit comments

Comments
 (0)