Skip to content

Commit

Permalink
Adding TabBars to enable search by rent or buy mode
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasmarques committed Apr 11, 2020
1 parent edff3ae commit f6eee11
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ class PropertyRepository(
searchMode = type.toString().toLowerCase(Locale.ROOT)
)
val response = domainApi.search(searchRequest)
return if (response.resultsReturned > 0) {
response.searchResults?.map { result ->
createProperty(result)
} ?: emptyList()
} else {
emptyList()
}
return response.searchResults?.filter {
it.listingType != "project"
}?.map { result ->
createProperty(result)
} ?: emptyList()
}

private fun createProperty(result: SearchResult) = Property(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.doug.domain.challenge.ui.properties

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.doug.domain.challenge.R
import com.doug.domain.challenge.repository.domain.SearchType
import com.doug.domain.challenge.ui.BaseFragment
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_main.*

class MainFragment : BaseFragment() {

private val rentFragment: PropertiesFragment by lazy {
PropertiesFragment.newInstance(SearchType.RENT)
}

private val buyFragment: PropertiesFragment by lazy {
PropertiesFragment.newInstance(SearchType.BUY)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_main, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
showRentFragment()
setUpTabSelectedListener()
}

private fun setUpTabSelectedListener() {
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab) {

}

override fun onTabUnselected(tab: TabLayout.Tab) {

}

override fun onTabSelected(tab: TabLayout.Tab) {
when (tab.position) {
0 -> showRentFragment()
1 -> showBuyFragment()
}
}
})
}

private fun showRentFragment() {
parentFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, rentFragment, "RentFragment").commit()
}

private fun showBuyFragment() {
parentFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, buyFragment, "BuyFragment").commit()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.core.os.bundleOf
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.doug.domain.challenge.R
Expand All @@ -15,16 +16,30 @@ import kotlinx.android.synthetic.main.fragment_properties.*

class PropertiesFragment : BaseFragment() {

private val viewModel by viewModels<PropertiesViewModel>()
companion object {
private const val TYPE = "TYPE"

fun newInstance(searchType: SearchType): PropertiesFragment {
return PropertiesFragment().apply {
arguments = bundleOf(
TYPE to searchType
)
}
}
}

private val viewModel by activityViewModels<PropertiesViewModel>()
private val adapter by lazy {
PropertiesAdapter()
}
private var selectedType = SearchType.RENT

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
selectedType = arguments?.get(TYPE) as? SearchType ?: SearchType.RENT
return inflater.inflate(R.layout.fragment_properties, container, false)
}

Expand All @@ -36,7 +51,7 @@ class PropertiesFragment : BaseFragment() {
observeViewModel()

// call view model to search the properties
viewModel.searchProperty(SearchType.RENT)
viewModel.searchProperty(selectedType)

}

Expand All @@ -53,7 +68,7 @@ class PropertiesFragment : BaseFragment() {
)
}
swipeRefreshLayout.setOnRefreshListener {
viewModel.searchProperty(SearchType.RENT)
viewModel.searchProperty(selectedType)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ class PropertiesViewModel constructor(
errorObserver.value = R.string.dialog_error_generic
}
}

override fun onCleared() {
super.onCleared()
}
}
3 changes: 2 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:elevation="0dp">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent">


<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/blue">

<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
style="@style/TabLayout"
android:background="@color/blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="enterAlways|scroll|snap"
app:tabMode="fixed">

<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/rent_tab" />

<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/buy_tab" />

</com.google.android.material.tabs.TabLayout>

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

<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
8 changes: 4 additions & 4 deletions app/src/main/res/navigation/navigation_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_graph"
app:startDestination="@id/propertiesFragment">
app:startDestination="@id/mainFragment">

<fragment
android:id="@+id/propertiesFragment"
android:name="com.doug.domain.challenge.ui.properties.PropertiesFragment"
android:id="@+id/mainFragment"
android:name="com.doug.domain.challenge.ui.properties.MainFragment"
android:label="@string/properties_title"
tools:layout="@layout/fragment_properties" />
tools:layout="@layout/fragment_main" />

</navigation>
3 changes: 2 additions & 1 deletion app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
<color name="colorAccent">@color/purple</color>

<color name="white">#ffffff</color>
<color name="white_transparent_40">#66FFFFFF</color>
<color name="grey">#f7f7f7</color>
<color name="black">#000000</color>
<color name="blue">#259be4</color>
<color name="purple">#b276c7</color>
<color name="darkBlue">#0A3B78</color>
<color name="darkBlue">#1a77d4</color>
</resources>
6 changes: 5 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
<string name="dialog_positive_button_label">OK</string>
<string name="dialog_error_generic">Sorry something went wrong please try again</string>

<!--Properties screen -->
<!--main fragment -->
<string name="rent_tab">Rent</string>
<string name="buy_tab">Buy</string>

<!--Properties fragment -->
<string name="empty_state">No properties found.</string>
<string name="details_text">%1$d bed, %2$d bath, %3$d car</string>
<string name="properties_title">Property List</string>
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,15 @@
<item name="android:textColorPrimary">@color/black</item>
</style>

<style name="TabLayout" parent="Widget.MaterialComponents.TabLayout">
<item name="tabSelectedTextColor">@color/white</item>
<item name="tabTextColor">@color/white_transparent_40</item>
<item name="tabIndicatorColor">@color/white</item>
<item name="tabBackground">@color/blue</item>
<item name="tabTextAppearance">@style/TabTextAppearance</item>
</style>

<style name="TabTextAppearance" parent="TextAppearance.Design.Tab">
<item name="android:textStyle">bold</item>
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.doug.domain.challenge.ui.properties

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.doug.domain.challenge.R
import com.doug.domain.challenge.repository.PropertyRepository
import com.doug.domain.challenge.repository.domain.Property
import com.doug.domain.challenge.repository.domain.SearchType
import com.doug.domain.challenge.test.CoroutinesTestRule
import com.doug.domain.challenge.test.data.PropertyTestDataFactory.createTestProperty
import com.doug.domain.challenge.test.testObserver
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.doThrow
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verifyBlocking
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -34,12 +36,7 @@ class PropertiesViewModelTest {
lateinit var viewModel: PropertiesViewModel

@Test
fun searchProperty() {

}

@Test
fun `factListObserver should be empty when the repository has no facts`() {
fun `listObserver should be empty when the repository has no property`() {
repository = mock {
onBlocking { search(SearchType.RENT) } doReturn emptyList()
}
Expand All @@ -59,7 +56,7 @@ class PropertiesViewModelTest {


@Test
fun `factListObserver should contain one fact when the repository returns one fact`() {
fun `listObserver should contain one property when the repository returns one property`() {
val properties = listOf(createTestProperty())
repository = mock {
onBlocking { search(SearchType.RENT) } doReturn properties
Expand All @@ -78,4 +75,23 @@ class PropertiesViewModelTest {
assertEquals(properties, viewModel.propertyListObserver.value)
assertEquals(1, viewModel.propertyListObserver.value?.size)
}

@Test
fun `error state should have the generic error when the repository throws an exception`() {
repository = mock {
onBlocking { search(SearchType.BUY) } doThrow (RuntimeException())
}
viewModel = PropertiesViewModel(repository)

viewModel.propertyListObserver.testObserver()
viewModel.errorObserver.testObserver()
viewModel.loadingObserver.testObserver()

viewModel.searchProperty(SearchType.BUY)
verifyBlocking(repository, { repository.search(SearchType.BUY) })

assertEquals(viewModel.errorObserver.value, R.string.dialog_error_generic)
assertEquals(viewModel.loadingObserver.value, false)
}

}

0 comments on commit f6eee11

Please sign in to comment.