2019-07-19 20:10:20 +02:00
|
|
|
package com.keylesspalace.tusky.components.search.fragments
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.view.View
|
|
|
|
import androidx.fragment.app.Fragment
|
2020-12-27 21:25:35 +01:00
|
|
|
import androidx.fragment.app.activityViewModels
|
2019-07-19 20:10:20 +02:00
|
|
|
import androidx.lifecycle.LiveData
|
|
|
|
import androidx.paging.PagedList
|
|
|
|
import androidx.paging.PagedListAdapter
|
|
|
|
import androidx.recyclerview.widget.DividerItemDecoration
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
2020-01-13 13:57:44 +01:00
|
|
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
2019-07-19 20:10:20 +02:00
|
|
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
|
|
import com.google.android.material.snackbar.Snackbar
|
|
|
|
import com.keylesspalace.tusky.AccountActivity
|
|
|
|
import com.keylesspalace.tusky.BottomSheetActivity
|
|
|
|
import com.keylesspalace.tusky.R
|
|
|
|
import com.keylesspalace.tusky.ViewTagActivity
|
|
|
|
import com.keylesspalace.tusky.components.search.SearchViewModel
|
|
|
|
import com.keylesspalace.tusky.di.Injectable
|
|
|
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
|
|
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
|
|
|
import com.keylesspalace.tusky.util.*
|
|
|
|
import kotlinx.android.synthetic.main.fragment_search.*
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
2020-12-27 21:25:35 +01:00
|
|
|
abstract class SearchFragment<T> : Fragment(R.layout.fragment_search),
|
2019-07-19 20:10:20 +02:00
|
|
|
LinkListener, Injectable, SwipeRefreshLayout.OnRefreshListener {
|
2019-11-17 20:58:54 +01:00
|
|
|
|
2019-07-19 20:10:20 +02:00
|
|
|
@Inject
|
|
|
|
lateinit var viewModelFactory: ViewModelFactory
|
|
|
|
|
2020-12-27 21:25:35 +01:00
|
|
|
protected val viewModel: SearchViewModel by activityViewModels { viewModelFactory }
|
2020-02-25 19:49:41 +01:00
|
|
|
|
|
|
|
private var snackbarErrorRetry: Snackbar? = null
|
2019-07-19 20:10:20 +02:00
|
|
|
|
|
|
|
abstract fun createAdapter(): PagedListAdapter<T, *>
|
|
|
|
|
|
|
|
abstract val networkStateRefresh: LiveData<NetworkState>
|
|
|
|
abstract val networkState: LiveData<NetworkState>
|
|
|
|
abstract val data: LiveData<PagedList<T>>
|
|
|
|
protected lateinit var adapter: PagedListAdapter<T, *>
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
initAdapter()
|
|
|
|
setupSwipeRefreshLayout()
|
|
|
|
subscribeObservables()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun setupSwipeRefreshLayout() {
|
|
|
|
swipeRefreshLayout.setOnRefreshListener(this)
|
|
|
|
swipeRefreshLayout.setColorSchemeResources(R.color.tusky_blue)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun subscribeObservables() {
|
2020-10-25 18:36:00 +01:00
|
|
|
data.observe(viewLifecycleOwner) {
|
2019-07-19 20:10:20 +02:00
|
|
|
adapter.submitList(it)
|
2020-10-25 18:36:00 +01:00
|
|
|
}
|
2019-07-19 20:10:20 +02:00
|
|
|
|
2020-10-25 18:36:00 +01:00
|
|
|
networkStateRefresh.observe(viewLifecycleOwner) {
|
2019-07-19 20:10:20 +02:00
|
|
|
|
|
|
|
searchProgressBar.visible(it == NetworkState.LOADING)
|
|
|
|
|
2020-01-13 13:57:44 +01:00
|
|
|
if (it.status == Status.FAILED) {
|
|
|
|
showError()
|
|
|
|
}
|
2019-07-19 20:10:20 +02:00
|
|
|
checkNoData()
|
2020-10-25 18:36:00 +01:00
|
|
|
}
|
2019-07-19 20:10:20 +02:00
|
|
|
|
2020-10-25 18:36:00 +01:00
|
|
|
networkState.observe(viewLifecycleOwner) {
|
2019-07-19 20:10:20 +02:00
|
|
|
|
|
|
|
progressBarBottom.visible(it == NetworkState.LOADING)
|
|
|
|
|
2020-01-13 13:57:44 +01:00
|
|
|
if (it.status == Status.FAILED) {
|
|
|
|
showError()
|
|
|
|
}
|
2020-10-25 18:36:00 +01:00
|
|
|
}
|
2019-07-19 20:10:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun checkNoData() {
|
|
|
|
showNoData(adapter.itemCount == 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun initAdapter() {
|
|
|
|
searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL))
|
|
|
|
searchRecyclerView.layoutManager = LinearLayoutManager(searchRecyclerView.context)
|
|
|
|
adapter = createAdapter()
|
|
|
|
searchRecyclerView.adapter = adapter
|
2020-01-13 13:57:44 +01:00
|
|
|
searchRecyclerView.setHasFixedSize(true)
|
|
|
|
(searchRecyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
2019-07-19 20:10:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun showNoData(isEmpty: Boolean) {
|
|
|
|
if (isEmpty && networkStateRefresh.value == NetworkState.LOADED)
|
|
|
|
searchNoResultsText.show()
|
|
|
|
else
|
|
|
|
searchNoResultsText.hide()
|
|
|
|
}
|
|
|
|
|
2020-01-13 13:57:44 +01:00
|
|
|
private fun showError() {
|
2019-07-19 20:10:20 +02:00
|
|
|
if (snackbarErrorRetry?.isShown != true) {
|
|
|
|
snackbarErrorRetry = Snackbar.make(layoutRoot, R.string.failed_search, Snackbar.LENGTH_INDEFINITE)
|
|
|
|
snackbarErrorRetry?.setAction(R.string.action_retry) {
|
|
|
|
snackbarErrorRetry = null
|
|
|
|
viewModel.retryAllSearches()
|
|
|
|
}
|
|
|
|
snackbarErrorRetry?.show()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onViewAccount(id: String) = startActivity(AccountActivity.getIntent(requireContext(), id))
|
|
|
|
|
|
|
|
override fun onViewTag(tag: String) = startActivity(ViewTagActivity.getIntent(requireContext(), tag))
|
|
|
|
|
|
|
|
override fun onViewUrl(url: String) {
|
|
|
|
bottomSheetActivity?.viewUrl(url)
|
|
|
|
}
|
|
|
|
|
2019-09-12 20:02:30 +02:00
|
|
|
protected val bottomSheetActivity
|
2020-01-13 13:57:44 +01:00
|
|
|
get() = (activity as? BottomSheetActivity)
|
2019-07-19 20:10:20 +02:00
|
|
|
|
|
|
|
override fun onRefresh() {
|
|
|
|
|
|
|
|
// Dismissed here because the RecyclerView bottomProgressBar is shown as soon as the retry begins.
|
2019-08-04 20:32:44 +02:00
|
|
|
swipeRefreshLayout.post {
|
2019-07-19 20:10:20 +02:00
|
|
|
swipeRefreshLayout.isRefreshing = false
|
|
|
|
}
|
|
|
|
viewModel.retryAllSearches()
|
|
|
|
}
|
|
|
|
}
|