diff --git a/app/src/main/java/com/doug/domain/challenge/repository/PropertyRepository.kt b/app/src/main/java/com/doug/domain/challenge/repository/PropertyRepository.kt index a7401d5..9a0f1ac 100644 --- a/app/src/main/java/com/doug/domain/challenge/repository/PropertyRepository.kt +++ b/app/src/main/java/com/doug/domain/challenge/repository/PropertyRepository.kt @@ -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( diff --git a/app/src/main/java/com/doug/domain/challenge/ui/properties/MainFragment.kt b/app/src/main/java/com/doug/domain/challenge/ui/properties/MainFragment.kt new file mode 100644 index 0000000..70360f7 --- /dev/null +++ b/app/src/main/java/com/doug/domain/challenge/ui/properties/MainFragment.kt @@ -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() + } + +} diff --git a/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesFragment.kt b/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesFragment.kt index 01f7684..2c0c36f 100644 --- a/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesFragment.kt +++ b/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesFragment.kt @@ -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 @@ -15,16 +16,30 @@ import kotlinx.android.synthetic.main.fragment_properties.* class PropertiesFragment : BaseFragment() { - private val viewModel by viewModels() + 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() 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) } @@ -36,7 +51,7 @@ class PropertiesFragment : BaseFragment() { observeViewModel() // call view model to search the properties - viewModel.searchProperty(SearchType.RENT) + viewModel.searchProperty(selectedType) } @@ -53,7 +68,7 @@ class PropertiesFragment : BaseFragment() { ) } swipeRefreshLayout.setOnRefreshListener { - viewModel.searchProperty(SearchType.RENT) + viewModel.searchProperty(selectedType) } } diff --git a/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesViewModel.kt b/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesViewModel.kt index 89fdcad..99fb332 100644 --- a/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesViewModel.kt +++ b/app/src/main/java/com/doug/domain/challenge/ui/properties/PropertiesViewModel.kt @@ -34,4 +34,8 @@ class PropertiesViewModel constructor( errorObserver.value = R.string.dialog_error_generic } } + + override fun onCleared() { + super.onCleared() + } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2d05340..a7625a3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,7 +11,8 @@ + android:layout_height="wrap_content" + app:elevation="0dp"> + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/navigation/navigation_graph.xml b/app/src/main/res/navigation/navigation_graph.xml index c34a293..0cdcca8 100644 --- a/app/src/main/res/navigation/navigation_graph.xml +++ b/app/src/main/res/navigation/navigation_graph.xml @@ -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"> + tools:layout="@layout/fragment_main" /> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bd84566..3bf836f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -5,9 +5,10 @@ @color/purple #ffffff + #66FFFFFF #f7f7f7 #000000 #259be4 #b276c7 - #0A3B78 + #1a77d4 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3acdf47..de35d65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,7 +6,11 @@ OK Sorry something went wrong please try again - + + Rent + Buy + + No properties found. %1$d bed, %2$d bath, %3$d car Property List diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ec7a053..2445c9b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -15,4 +15,15 @@ @color/black + + + diff --git a/app/src/test/java/com/doug/domain/challenge/ui/properties/PropertiesViewModelTest.kt b/app/src/test/java/com/doug/domain/challenge/ui/properties/PropertiesViewModelTest.kt index 01b1673..688c342 100644 --- a/app/src/test/java/com/doug/domain/challenge/ui/properties/PropertiesViewModelTest.kt +++ b/app/src/test/java/com/doug/domain/challenge/ui/properties/PropertiesViewModelTest.kt @@ -1,6 +1,7 @@ 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 @@ -8,10 +9,11 @@ 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 @@ -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() } @@ -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 @@ -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) + } + }