Skip to content

Commit ebb9cf8

Browse files
format property detail
1 parent 29b3529 commit ebb9cf8

File tree

9 files changed

+330
-29
lines changed

9 files changed

+330
-29
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ Sample project that build with MVVM clean architure and various cool techs inclu
1111

1212
Unit tests are written with JUnit4, JUnit5, MockK, Truth, MockWebServer.
1313

14-
| Flow | RxJava3 | Pagination | Favorites
14+
| Flow | RxJava3 | Pagination
1515
| ------------------|-------------| -----|--------------|
16-
| <img src="./screenshots/property_flow.png"/> | <img src="./screenshots/property_rxjava3.png"/> | <img src="./screenshots/property_pagination.png"/> |<img src="./screenshots/favorites.png"/> |
16+
| <img src="./screenshots/property_flow.png"/> | <img src="./screenshots/property_rxjava3.png"/> | <img src="./screenshots/property_pagination.png"/> |
1717

1818

1919
## Overview

buildSrc/src/main/java/extension/DependencyHandlerExtension.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fun DependencyHandler.addAppModuleDependencies() {
5353
implementation(Deps.COROUTINES_ANDROID)
5454

5555
// Leak Canary
56-
debugImplementation(Deps.LEAK_CANARY)
56+
// debugImplementation(Deps.LEAK_CANARY)
5757

5858
// Room
5959
implementation(Deps.ROOM_RUNTIME)

features/home/src/main/java/com/smarttoolfactory/home/HomeFragment.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ class SortDialogFragment : DialogFragment() {
183183

184184
private var currentItem = 0
185185
private var checkedItem = currentItem
186+
private var canceled = false
186187

187188
override fun onCreate(savedInstanceState: Bundle?) {
188189
super.onCreate(savedInstanceState)
@@ -193,32 +194,32 @@ class SortDialogFragment : DialogFragment() {
193194

194195
currentItem = viewModel.sortPropertyList.indexOf(viewModel.currentSortFilter)
195196
checkedItem = currentItem
197+
canceled = false
196198

197199
val builder = AlertDialog.Builder(requireActivity())
198200
builder.setTitle("Sorting")
199201
.setNegativeButton("CANCEL") { dialog, which ->
202+
canceled = true
200203
dismiss()
201204
}
202205
.setSingleChoiceItems(
203206
viewModel.sortFilterNames.toTypedArray(),
204207
currentItem
205208
) { dialog, which ->
206209
checkedItem = which
207-
}.setOnDismissListener {
208210

209211
// Alternative 1 works as soon as user changes the option
210-
// if (currentItem != checkedItem) {
212+
// if (currentItem != checkedItem) {
211213
// viewModel.queryBySort.value = Event(viewModel.sortPropertyList[checkedItem])
212214
// }
213-
// dismiss()
214215
}
215216
return builder.create()
216217
}
217218

218219
override fun onDismiss(dialog: DialogInterface) {
219220
super.onDismiss(dialog)
220221
// Alternative works after dialog is dismissed
221-
if (currentItem != checkedItem) {
222+
if (currentItem != checkedItem && !canceled) {
222223
viewModel.queryBySort.value = Event(viewModel.sortPropertyList[checkedItem])
223224
}
224225
}

features/property_detail/src/main/java/com/smarttoolfactory/property_detail/PropertyDetailFragment.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.smarttoolfactory.property_detail
22

33
import android.os.Bundle
4+
import androidx.fragment.app.activityViewModels
5+
import androidx.navigation.NavController
46
import com.smarttoolfactory.core.di.CoreModuleDependencies
57
import com.smarttoolfactory.core.ui.fragment.DynamicNavigationFragment
8+
import com.smarttoolfactory.core.viewmodel.NavControllerViewModel
69
import com.smarttoolfactory.domain.model.PropertyItem
710
import com.smarttoolfactory.property_detail.databinding.FragmentPropertyDetailBinding
811
import com.smarttoolfactory.property_detail.di.DaggerPropertyDetailComponent
@@ -16,6 +19,11 @@ class PropertyDetailFragment : DynamicNavigationFragment<FragmentPropertyDetailB
1619
@Inject
1720
lateinit var viewModel: PropertyDetailViewModel
1821

22+
/**
23+
* ViwModel for getting [NavController] for setting Toolbar navigation
24+
*/
25+
private val navControllerViewModel by activityViewModels<NavControllerViewModel>()
26+
1927
override fun bindViews() {
2028
// Get Post from navigation component arguments
2129
val property = arguments?.get("property") as PropertyItem
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.smarttoolfactory.property_detail
2+
3+
import android.view.View
4+
import android.widget.ImageView
5+
import androidx.databinding.BindingAdapter
6+
import androidx.recyclerview.widget.ListAdapter
7+
import androidx.recyclerview.widget.RecyclerView
8+
import com.bumptech.glide.Glide
9+
import com.bumptech.glide.request.RequestOptions
10+
import com.smarttoolfactory.domain.model.PropertyItem
11+
12+
/*
13+
*** Bindings for RecyclerView ***
14+
*/
15+
16+
/**
17+
* [BindingAdapter]s for the [PropertyItem]s to ListAdapter.
18+
*/
19+
@BindingAdapter("app:items")
20+
fun RecyclerView.setItems(items: List<PropertyItem>?) {
21+
22+
items?.let {
23+
(adapter as ListAdapter<PropertyItem, *>)?.submitList(items)
24+
}
25+
}
26+
27+
/**
28+
* Binding adapter used with this class android:src used with binding of this object
29+
* loads image from url into specified view
30+
*
31+
* @param view image to be loaded into
32+
* @param path of the image to be fetched
33+
*/
34+
@BindingAdapter("imageSrc")
35+
fun setImageUrl(view: ImageView, path: String?) {
36+
37+
try {
38+
39+
val requestOptions = RequestOptions()
40+
requestOptions.placeholder(R.drawable.placeholder)
41+
42+
Glide
43+
.with(view.context)
44+
.setDefaultRequestOptions(requestOptions)
45+
.load(path)
46+
.into(view)
47+
} catch (e: Exception) {
48+
e.printStackTrace()
49+
}
50+
}
51+
52+
/**
53+
* Display or hide a view based on a condition
54+
*
55+
* @param condition if it's true this View's visibility is set to [View.VISIBLE]
56+
*/
57+
@BindingAdapter("visibilityBasedOn")
58+
fun View.visibilityBasedOn(condition: Boolean) {
59+
visibility = if (condition) View.VISIBLE else View.GONE
60+
}
-103 KB
Binary file not shown.
2.4 KB
Loading

features/property_detail/src/main/res/layout/fragment_property_detail.xml

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,141 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<layout>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools">
35

46
<data>
7+
58
<variable
69
name="item"
710
type="com.smarttoolfactory.domain.model.PropertyItem" />
811
</data>
912

10-
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
11-
xmlns:app="http://schemas.android.com/apk/res-auto"
13+
<androidx.coordinatorlayout.widget.CoordinatorLayout
1214
android:layout_width="match_parent"
1315
android:layout_height="match_parent">
1416

15-
1617
<com.google.android.material.appbar.AppBarLayout
1718
android:id="@+id/appbar"
1819
android:layout_width="match_parent"
19-
android:layout_height="wrap_content">
20+
android:layout_height="256dp"
21+
android:fitsSystemWindows="true"
22+
android:theme="@style/ThemeOverlay.AppCompat.ActionBar">
2023

2124
<com.google.android.material.appbar.CollapsingToolbarLayout
2225
android:id="@+id/collapsingToolbar"
2326
android:layout_width="match_parent"
24-
android:layout_height="200dp"
25-
app:contentScrim="?attr/colorPrimary"
27+
android:layout_height="wrap_content"
28+
app:contentScrim="@color/white"
2629
app:expandedTitleMarginEnd="64dp"
2730
app:expandedTitleMarginStart="48dp"
2831
app:layout_scrollFlags="scroll|exitUntilCollapsed">
2932

30-
31-
<androidx.appcompat.widget.Toolbar
32-
android:id="@+id/toolbar"
33+
<androidx.constraintlayout.widget.ConstraintLayout
3334
android:layout_width="match_parent"
34-
android:layout_height="?attr/actionBarSize"
35-
app:layout_collapseMode="parallax" />
35+
android:layout_height="match_parent">
36+
37+
<ImageView
38+
android:id="@+id/ivHeader"
39+
imageSrc="@{item.thumbnailBig}"
40+
android:layout_width="wrap_content"
41+
android:layout_height="match_parent"
42+
android:scaleType="centerCrop"
43+
android:src="@drawable/placeholder"
44+
app:layout_constraintBottom_toBottomOf="parent"
45+
app:layout_constraintEnd_toEndOf="parent"
46+
app:layout_constraintStart_toStartOf="parent"
47+
app:layout_constraintTop_toTopOf="parent" />
48+
49+
<TextView
50+
visibilityBasedOn="@{item.verified}"
51+
android:layout_width="wrap_content"
52+
android:layout_height="wrap_content"
53+
android:background="#66BB6A"
54+
android:paddingStart="10dp"
55+
android:paddingTop="2dp"
56+
android:paddingEnd="10dp"
57+
android:paddingBottom="2dp"
58+
android:text="VERIFIED"
59+
android:textColor="@color/white"
60+
android:textSize="16sp"
61+
android:translationZ="5dp"
62+
app:layout_constraintBottom_toBottomOf="@id/ivHeader"
63+
app:layout_constraintEnd_toEndOf="parent"
64+
app:layout_constraintStart_toStartOf="parent" />
65+
66+
</androidx.constraintlayout.widget.ConstraintLayout>
67+
3668
</com.google.android.material.appbar.CollapsingToolbarLayout>
3769

3870

3971
</com.google.android.material.appbar.AppBarLayout>
4072

41-
42-
<androidx.constraintlayout.widget.ConstraintLayout
73+
<androidx.core.widget.NestedScrollView
4374
android:layout_width="match_parent"
4475
android:layout_height="match_parent"
76+
4577
app:layout_behavior="@string/appbar_scrolling_view_behavior">
4678

4779
<LinearLayout
48-
android:layout_width="wrap_content"
49-
android:layout_height="3000dp"
50-
android:background="#f00"
51-
app:layout_constraintEnd_toEndOf="parent"
52-
app:layout_constraintStart_toStartOf="parent"
53-
app:layout_constraintTop_toTopOf="parent" />
54-
55-
</androidx.constraintlayout.widget.ConstraintLayout>
80+
android:layout_width="match_parent"
81+
android:layout_height="match_parent"
82+
android:orientation="vertical"
83+
android:paddingStart="16dp"
84+
android:paddingEnd="16dp">
85+
86+
<com.google.android.material.textview.MaterialTextView
87+
android:id="@+id/tvPrice"
88+
android:layout_width="match_parent"
89+
android:layout_height="wrap_content"
90+
android:layout_marginTop="12dp"
91+
android:gravity="center"
92+
android:maxLines="1"
93+
android:text="@{item.price + ` `+ item.currency}"
94+
android:textColor="@color/black"
95+
android:textSize="24sp"
96+
tools:text="249,000 AED" />
97+
98+
<com.google.android.material.textview.MaterialTextView
99+
android:id="@+id/tvTitle"
100+
android:layout_width="match_parent"
101+
android:layout_height="wrap_content"
102+
android:layout_marginTop="12dp"
103+
android:gravity="center"
104+
android:maxLines="1"
105+
android:text="@{item.title}"
106+
android:textColor="@color/black"
107+
android:textSize="16sp"
108+
tools:text="Apartment, 1 bed, 2 baths" />
109+
110+
<com.google.android.material.textview.MaterialTextView
111+
android:id="@+id/tvLocation"
112+
android:layout_width="match_parent"
113+
android:layout_height="wrap_content"
114+
android:layout_marginTop="16dp"
115+
android:gravity="center"
116+
android:maxLines="2"
117+
android:text="@{item.location}"
118+
android:textColor="#000"
119+
tools:text="Casa, Arabian Ranches 2, Dubai" />
120+
121+
122+
<com.google.android.material.textview.MaterialTextView
123+
android:id="@+id/tvDescription"
124+
android:layout_width="match_parent"
125+
android:layout_height="wrap_content"
126+
android:layout_gravity="center_horizontal"
127+
android:layout_marginTop="16dp"
128+
129+
android:gravity="center"
130+
android:maxLines="2"
131+
android:text="@{item.subject}"
132+
133+
android:textColor="#000"
134+
tools:text="Stunning 1 Bed Apt with Burj Khalifa View" />
135+
136+
</LinearLayout>
137+
138+
</androidx.core.widget.NestedScrollView>
56139

57140

58141
</androidx.coordinatorlayout.widget.CoordinatorLayout>

0 commit comments

Comments
 (0)