diff --git a/README.md b/README.md index be08be3..f705472 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # Rocket Science [![CircleCI](https://circleci.com/gh/melihaksoy/RocketScience/tree/master.svg?style=svg&circle-token=705e399a0116be0a5bb10bddc72fc7ef19b568e3)](https://circleci.com/gh/melihaksoy/RocketScience/tree/master) +[![codebeat badge](https://codebeat.co/badges/b009ceb8-bc61-4a17-b7f1-8321dd155ed9)](https://codebeat.co/a/melih-aksoy/projects/github-com-melihaksoy-rocketscience-master) diff --git a/core/src/main/kotlin/com/melih/core/base/lifecycle/BaseFragment.kt b/core/src/main/kotlin/com/melih/core/base/lifecycle/BaseFragment.kt index 86f2ed9..7dce574 100644 --- a/core/src/main/kotlin/com/melih/core/base/lifecycle/BaseFragment.kt +++ b/core/src/main/kotlin/com/melih/core/base/lifecycle/BaseFragment.kt @@ -10,6 +10,9 @@ import androidx.databinding.ViewDataBinding import androidx.fragment.app.Fragment import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment +import com.google.android.material.snackbar.Snackbar +import com.melih.repository.interactors.base.Reason +import kotlinx.coroutines.ExperimentalCoroutinesApi /** * Parent of all fragments. @@ -38,6 +41,17 @@ abstract class BaseFragment : Fragment() { return binding.root } + @ExperimentalCoroutinesApi + protected fun showSnackbarWithAction(reason: Reason, block: () -> Unit) { + Snackbar.make( + binding.root, + resources.getString(reason.messageRes), + Snackbar.LENGTH_INDEFINITE + ).setAction(com.melih.core.R.string.retry) { + block() + }.show() + } + @LayoutRes abstract fun getLayoutId(): Int // endregion diff --git a/core/src/main/kotlin/com/melih/core/extensions/UtilityExtension.kt b/core/src/main/kotlin/com/melih/core/extensions/UtilityExtension.kt new file mode 100644 index 0000000..4413e8a --- /dev/null +++ b/core/src/main/kotlin/com/melih/core/extensions/UtilityExtension.kt @@ -0,0 +1,3 @@ +package com.melih.core.extensions + +fun CharSequence.containsIgnoreCase(other: CharSequence) = contains(other, true) diff --git a/features/detail/src/main/kotlin/com/melih/detail/ui/DetailFragment.kt b/features/detail/src/main/kotlin/com/melih/detail/ui/DetailFragment.kt index 204ebbf..d24846e 100644 --- a/features/detail/src/main/kotlin/com/melih/detail/ui/DetailFragment.kt +++ b/features/detail/src/main/kotlin/com/melih/detail/ui/DetailFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.text.method.ScrollingMovementMethod import android.view.View import androidx.navigation.fragment.navArgs -import com.google.android.material.snackbar.Snackbar import com.melih.core.base.lifecycle.BaseDaggerFragment import com.melih.core.extensions.createFor import com.melih.core.extensions.observe @@ -43,13 +42,9 @@ class DetailFragment : BaseDaggerFragment() { // Observing error to show toast with retry action observe(viewModel.errorData) { - Snackbar.make( - binding.root, - resources.getString(it.messageRes), - Snackbar.LENGTH_INDEFINITE - ).setAction(com.melih.core.R.string.retry) { + showSnackbarWithAction(it) { viewModel.retry() - }.show() + } } observe(viewModel.successData) { diff --git a/features/list/src/main/kotlin/com/melih/list/ui/LaunchesFragment.kt b/features/list/src/main/kotlin/com/melih/list/ui/LaunchesFragment.kt index bda4dc9..c3e8a65 100644 --- a/features/list/src/main/kotlin/com/melih/list/ui/LaunchesFragment.kt +++ b/features/list/src/main/kotlin/com/melih/list/ui/LaunchesFragment.kt @@ -6,9 +6,9 @@ import android.view.MenuInflater import android.view.View import androidx.appcompat.widget.SearchView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import com.google.android.material.snackbar.Snackbar import com.melih.core.actions.Actions import com.melih.core.base.lifecycle.BaseDaggerFragment +import com.melih.core.extensions.containsIgnoreCase import com.melih.core.extensions.createFor import com.melih.core.extensions.observe import com.melih.list.R @@ -16,7 +16,6 @@ import com.melih.list.databinding.ListBinding import com.melih.repository.entities.LaunchEntity import com.melih.repository.interactors.base.Result import kotlinx.coroutines.ExperimentalCoroutinesApi -import timber.log.Timber class LaunchesFragment : BaseDaggerFragment(), SwipeRefreshLayout.OnRefreshListener { @@ -40,32 +39,7 @@ class LaunchesFragment : BaseDaggerFragment(), SwipeRefreshLayout.O binding.rocketList.adapter = launchesAdapter binding.swipeRefreshLayout.setOnRefreshListener(this) - // Observing state to show loading - observe(viewModel.stateData) { - binding.swipeRefreshLayout.isRefreshing = it is Result.State.Loading - } - - // Observing error to show toast with retry action - observe(viewModel.errorData) { - Snackbar.make( - binding.root, - resources.getString(it.messageRes), - Snackbar.LENGTH_INDEFINITE - ).setAction(com.melih.core.R.string.retry) { - viewModel.retry() - }.show() - } - - observe(viewModel.successData) { - itemList.addAll(it) - launchesAdapter.submitList(itemList) - binding.rocketList.scheduleLayoutAnimation() - } - } - - private fun onItemSelected(item: LaunchEntity) { - Timber.i("${item.id}") - startActivity(Actions.openDetailFor(item.id)) + observeDataChanges() } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -80,22 +54,7 @@ class LaunchesFragment : BaseDaggerFragment(), SwipeRefreshLayout.O } override fun onQueryTextChange(newText: String?): Boolean { - launchesAdapter.submitList( - if (!newText.isNullOrBlank()) { - itemList.filter { - it.rocket.name.contains( - newText, - true - ) || (it.missions.size > 0 && it.missions[0].description.contains( - newText, - true - )) - } - } else { - itemList - } - ) - + launchesAdapter.submitList(filterItemListBy(newText)) return true } }) @@ -104,6 +63,41 @@ class LaunchesFragment : BaseDaggerFragment(), SwipeRefreshLayout.O super.onCreateOptionsMenu(menu, inflater) } + @ExperimentalCoroutinesApi + private fun observeDataChanges() { + + // Observing state to show loading + observe(viewModel.stateData) { + binding.swipeRefreshLayout.isRefreshing = it is Result.State.Loading + } + + // Observing error to show toast with retry action + observe(viewModel.errorData) { + showSnackbarWithAction(it) { + viewModel.retry() + } + } + + observe(viewModel.successData) { + itemList.addAll(it) + launchesAdapter.submitList(itemList) + binding.rocketList.scheduleLayoutAnimation() + } + } + + private fun onItemSelected(item: LaunchEntity) { + startActivity(Actions.openDetailFor(item.id)) + } + + private fun filterItemListBy(query: String?) = + if (!query.isNullOrBlank()) { + itemList.filter { + it.rocket.name.containsIgnoreCase(query) || it.missions.any { it.description.containsIgnoreCase(query) } + } + } else { + itemList + } + @ExperimentalCoroutinesApi override fun onRefresh() { viewModel.refresh()