Refactor "trending hashtags" code (#3595)
- Fix codeformatting - Add new refreshing state - Disable LogConditional lint rule - Update lint-baseline
This commit is contained in:
parent
071e00774e
commit
f23c0cc634
13 changed files with 335 additions and 480 deletions
|
|
@ -19,23 +19,19 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.commit
|
||||
import com.keylesspalace.tusky.BottomSheetActivity
|
||||
import com.keylesspalace.tusky.BaseActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.databinding.ActivityTrendingBinding
|
||||
import com.keylesspalace.tusky.util.viewBinding
|
||||
import dagger.android.DispatchingAndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import javax.inject.Inject
|
||||
|
||||
class TrendingActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||
class TrendingActivity : BaseActivity(), HasAndroidInjector {
|
||||
|
||||
@Inject
|
||||
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
private val binding: ActivityTrendingBinding by viewBinding(ActivityTrendingBinding::inflate)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -44,10 +40,8 @@ class TrendingActivity : BottomSheetActivity(), HasAndroidInjector {
|
|||
|
||||
setSupportActionBar(binding.includedToolbar.toolbar)
|
||||
|
||||
val title = getString(R.string.title_public_trending_hashtags)
|
||||
|
||||
supportActionBar?.run {
|
||||
setTitle(title)
|
||||
setTitle(R.string.title_public_trending_hashtags)
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
|
@ -63,10 +57,6 @@ class TrendingActivity : BottomSheetActivity(), HasAndroidInjector {
|
|||
override fun androidInjector() = dispatchingAndroidInjector
|
||||
|
||||
companion object {
|
||||
const val TAG = "TrendingActivity"
|
||||
|
||||
@JvmStatic
|
||||
fun getIntent(context: Context) =
|
||||
Intent(context, TrendingActivity::class.java)
|
||||
fun getIntent(context: Context) = Intent(context, TrendingActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,12 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.adapter.TrendingDateViewHolder
|
||||
import com.keylesspalace.tusky.adapter.TrendingTagViewHolder
|
||||
import com.keylesspalace.tusky.databinding.ItemTrendingCellBinding
|
||||
import com.keylesspalace.tusky.databinding.ItemTrendingDateBinding
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.viewdata.TrendingViewData
|
||||
|
||||
class TrendingAdapter(
|
||||
private val trendingListener: LinkListener
|
||||
private val onViewTag: (String) -> Unit
|
||||
) : ListAdapter<TrendingViewData, RecyclerView.ViewHolder>(TrendingDifferCallback) {
|
||||
|
||||
init {
|
||||
|
|
@ -42,7 +39,6 @@ class TrendingAdapter(
|
|||
ItemTrendingCellBinding.inflate(LayoutInflater.from(viewGroup.context))
|
||||
TrendingTagViewHolder(binding)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val binding =
|
||||
ItemTrendingDateBinding.inflate(LayoutInflater.from(viewGroup.context))
|
||||
|
|
@ -52,38 +48,15 @@ class TrendingAdapter(
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
|
||||
bindViewHolder(viewHolder, position, null)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
position: Int,
|
||||
payloads: List<*>
|
||||
) {
|
||||
bindViewHolder(viewHolder, position, payloads)
|
||||
}
|
||||
|
||||
private fun bindViewHolder(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
position: Int,
|
||||
payloads: List<*>?
|
||||
) {
|
||||
when (val header = getItem(position)) {
|
||||
when (val viewData = getItem(position)) {
|
||||
is TrendingViewData.Tag -> {
|
||||
val maxTrendingValue = currentList
|
||||
.flatMap { trendingViewData ->
|
||||
trendingViewData.asTagOrNull()?.tag?.history.orEmpty()
|
||||
}
|
||||
.mapNotNull { it.uses.toLongOrNull() }
|
||||
.maxOrNull() ?: 1
|
||||
|
||||
val holder = viewHolder as TrendingTagViewHolder
|
||||
holder.setup(header, maxTrendingValue, trendingListener)
|
||||
holder.setup(viewData, onViewTag)
|
||||
}
|
||||
|
||||
is TrendingViewData.Header -> {
|
||||
val holder = viewHolder as TrendingDateViewHolder
|
||||
holder.setup(header.start, header.end)
|
||||
holder.setup(viewData.start, viewData.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,14 +85,7 @@ class TrendingAdapter(
|
|||
oldItem: TrendingViewData,
|
||||
newItem: TrendingViewData
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getChangePayload(
|
||||
oldItem: TrendingViewData,
|
||||
newItem: TrendingViewData
|
||||
): Any? {
|
||||
return null
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/* Copyright 2023 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.components.trending
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemTrendingDateBinding
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
class TrendingDateViewHolder(
|
||||
private val binding: ItemTrendingDateBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private val dateFormat = SimpleDateFormat("EEE dd MMM yyyy", Locale.getDefault()).apply {
|
||||
this.timeZone = TimeZone.getDefault()
|
||||
}
|
||||
|
||||
fun setup(start: Date, end: Date) {
|
||||
binding.dates.text = itemView.context.getString(
|
||||
R.string.date_range,
|
||||
dateFormat.format(start),
|
||||
dateFormat.format(end)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,17 +15,14 @@
|
|||
|
||||
package com.keylesspalace.tusky.components.trending
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
|
||||
|
|
@ -33,18 +30,14 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
|
||||
import at.connyduck.sparkbutton.helpers.Utils
|
||||
import com.keylesspalace.tusky.BottomSheetActivity
|
||||
import com.keylesspalace.tusky.PostLookupFallbackBehavior
|
||||
import com.keylesspalace.tusky.BaseActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.StatusListActivity
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.components.trending.viewmodel.TrendingViewModel
|
||||
import com.keylesspalace.tusky.databinding.FragmentTrendingBinding
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.interfaces.RefreshableFragment
|
||||
import com.keylesspalace.tusky.interfaces.ReselectableFragment
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
|
|
@ -56,48 +49,20 @@ import kotlinx.coroutines.launch
|
|||
import javax.inject.Inject
|
||||
|
||||
class TrendingFragment :
|
||||
Fragment(),
|
||||
Fragment(R.layout.fragment_trending),
|
||||
OnRefreshListener,
|
||||
LinkListener,
|
||||
Injectable,
|
||||
ReselectableFragment,
|
||||
RefreshableFragment {
|
||||
|
||||
private lateinit var bottomSheetActivity: BottomSheetActivity
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
private val viewModel: TrendingViewModel by lazy {
|
||||
ViewModelProvider(this, viewModelFactory)[TrendingViewModel::class.java]
|
||||
}
|
||||
private val viewModel: TrendingViewModel by viewModels { viewModelFactory }
|
||||
|
||||
private val binding by viewBinding(FragmentTrendingBinding::bind)
|
||||
|
||||
private lateinit var adapter: TrendingAdapter
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
bottomSheetActivity = if (context is BottomSheetActivity) {
|
||||
context
|
||||
} else {
|
||||
throw IllegalStateException("Fragment must be attached to a BottomSheetActivity!")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
adapter = TrendingAdapter(
|
||||
this
|
||||
)
|
||||
}
|
||||
private val adapter = TrendingAdapter(::onViewTag)
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
|
@ -106,14 +71,6 @@ class TrendingFragment :
|
|||
setupLayoutManager(columnCount)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_trending, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
setupSwipeRefreshLayout()
|
||||
setupRecyclerView()
|
||||
|
|
@ -175,25 +132,19 @@ class TrendingFragment :
|
|||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
viewModel.invalidate()
|
||||
viewModel.invalidate(true)
|
||||
}
|
||||
|
||||
override fun onViewUrl(url: String) {
|
||||
bottomSheetActivity.viewUrl(url, PostLookupFallbackBehavior.OPEN_IN_BROWSER)
|
||||
}
|
||||
|
||||
override fun onViewTag(tag: String) {
|
||||
bottomSheetActivity.startActivityWithSlideInAnimation(StatusListActivity.newHashtagIntent(requireContext(), tag))
|
||||
}
|
||||
|
||||
override fun onViewAccount(id: String) {
|
||||
bottomSheetActivity.viewAccount(id)
|
||||
fun onViewTag(tag: String) {
|
||||
(requireActivity() as BaseActivity).startActivityWithSlideInAnimation(StatusListActivity.newHashtagIntent(requireContext(), tag))
|
||||
}
|
||||
|
||||
private fun processViewState(uiState: TrendingViewModel.TrendingUiState) {
|
||||
Log.d(TAG, uiState.loadingState.name)
|
||||
when (uiState.loadingState) {
|
||||
TrendingViewModel.LoadingState.INITIAL -> clearLoadingState()
|
||||
TrendingViewModel.LoadingState.LOADING -> applyLoadingState()
|
||||
TrendingViewModel.LoadingState.REFRESHING -> applyRefreshingState()
|
||||
TrendingViewModel.LoadingState.LOADED -> applyLoadedState(uiState.trendingViewData)
|
||||
TrendingViewModel.LoadingState.ERROR_NETWORK -> networkError()
|
||||
TrendingViewModel.LoadingState.ERROR_OTHER -> otherError()
|
||||
|
|
@ -203,8 +154,9 @@ class TrendingFragment :
|
|||
private fun applyLoadedState(viewData: List<TrendingViewData>) {
|
||||
clearLoadingState()
|
||||
|
||||
adapter.submitList(viewData)
|
||||
|
||||
if (viewData.isEmpty()) {
|
||||
adapter.submitList(emptyList())
|
||||
binding.recyclerView.hide()
|
||||
binding.messageView.show()
|
||||
binding.messageView.setup(
|
||||
|
|
@ -213,16 +165,16 @@ class TrendingFragment :
|
|||
null
|
||||
)
|
||||
} else {
|
||||
val viewDataWithDates = listOf(viewData.first().asHeaderOrNull()) + viewData
|
||||
|
||||
adapter.submitList(viewDataWithDates)
|
||||
|
||||
binding.recyclerView.show()
|
||||
binding.messageView.hide()
|
||||
}
|
||||
binding.progressBar.hide()
|
||||
}
|
||||
|
||||
private fun applyRefreshingState() {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
}
|
||||
|
||||
private fun applyLoadingState() {
|
||||
binding.recyclerView.hide()
|
||||
binding.messageView.hide()
|
||||
|
|
@ -297,8 +249,6 @@ class TrendingFragment :
|
|||
companion object {
|
||||
private const val TAG = "TrendingFragment"
|
||||
|
||||
fun newInstance(): TrendingFragment {
|
||||
return TrendingFragment()
|
||||
}
|
||||
fun newInstance() = TrendingFragment()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright 2023 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.components.trending
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemTrendingCellBinding
|
||||
import com.keylesspalace.tusky.util.formatNumber
|
||||
import com.keylesspalace.tusky.viewdata.TrendingViewData
|
||||
|
||||
class TrendingTagViewHolder(
|
||||
private val binding: ItemTrendingCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun setup(
|
||||
tagViewData: TrendingViewData.Tag,
|
||||
onViewTag: (String) -> Unit
|
||||
) {
|
||||
binding.tag.text = binding.root.context.getString(R.string.title_tag, tagViewData.name)
|
||||
|
||||
binding.graph.maxTrendingValue = tagViewData.maxTrendingValue
|
||||
binding.graph.primaryLineData = tagViewData.usage
|
||||
binding.graph.secondaryLineData = tagViewData.accounts
|
||||
|
||||
binding.totalUsage.text = formatNumber(tagViewData.usage.sum(), 1000)
|
||||
|
||||
val totalAccounts = tagViewData.accounts.sum()
|
||||
binding.totalAccounts.text = formatNumber(totalAccounts, 1000)
|
||||
|
||||
binding.currentUsage.text = tagViewData.usage.last().toString()
|
||||
binding.currentAccounts.text = tagViewData.usage.last().toString()
|
||||
|
||||
itemView.setOnClickListener {
|
||||
onViewTag(tagViewData.name)
|
||||
}
|
||||
|
||||
itemView.contentDescription =
|
||||
itemView.context.getString(
|
||||
R.string.accessibility_talking_about_tag,
|
||||
totalAccounts,
|
||||
tagViewData.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,11 +15,15 @@
|
|||
|
||||
package com.keylesspalace.tusky.components.trending.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
import com.keylesspalace.tusky.entity.Filter
|
||||
import com.keylesspalace.tusky.entity.end
|
||||
import com.keylesspalace.tusky.entity.start
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.toViewData
|
||||
import com.keylesspalace.tusky.viewdata.TrendingViewData
|
||||
|
|
@ -28,7 +32,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.launch
|
||||
import okio.IOException
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class TrendingViewModel @Inject constructor(
|
||||
|
|
@ -36,7 +40,7 @@ class TrendingViewModel @Inject constructor(
|
|||
private val eventHub: EventHub
|
||||
) : ViewModel() {
|
||||
enum class LoadingState {
|
||||
INITIAL, LOADING, LOADED, ERROR_NETWORK, ERROR_OTHER
|
||||
INITIAL, LOADING, REFRESHING, LOADED, ERROR_NETWORK, ERROR_OTHER
|
||||
}
|
||||
|
||||
data class TrendingUiState(
|
||||
|
|
@ -67,37 +71,43 @@ class TrendingViewModel @Inject constructor(
|
|||
*
|
||||
* A tag is excluded if it is filtered by the user on their home timeline.
|
||||
*/
|
||||
fun invalidate() = viewModelScope.launch {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.LOADING)
|
||||
|
||||
try {
|
||||
val deferredFilters = async { mastodonApi.getFilters() }
|
||||
val response = mastodonApi.trendingTags()
|
||||
if (!response.isSuccessful) {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_NETWORK)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val homeFilters = deferredFilters.await().getOrNull()?.filter {
|
||||
it.context.contains(Filter.Kind.HOME.kind)
|
||||
}
|
||||
|
||||
val tags = response.body()!!
|
||||
.filter {
|
||||
homeFilters?.none { filter ->
|
||||
filter.keywords.any { keyword -> keyword.keyword.equals(it.name, ignoreCase = true) }
|
||||
} ?: false
|
||||
}
|
||||
.sortedBy { tag -> tag.history.sumOf { it.uses.toLongOrNull() ?: 0 } }
|
||||
.map { it.toViewData() }
|
||||
.asReversed()
|
||||
|
||||
_uiState.value = TrendingUiState(tags, LoadingState.LOADED)
|
||||
} catch (e: IOException) {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_NETWORK)
|
||||
} catch (e: Exception) {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_OTHER)
|
||||
fun invalidate(refresh: Boolean = false) = viewModelScope.launch {
|
||||
if (refresh) {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.REFRESHING)
|
||||
} else {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.LOADING)
|
||||
}
|
||||
|
||||
val deferredFilters = async { mastodonApi.getFilters() }
|
||||
|
||||
mastodonApi.trendingTags().fold(
|
||||
{ tagResponse ->
|
||||
val homeFilters = deferredFilters.await().getOrNull()?.filter { filter ->
|
||||
filter.context.contains(Filter.Kind.HOME.kind)
|
||||
}
|
||||
val tags = tagResponse
|
||||
.filter { tag ->
|
||||
homeFilters?.none { filter ->
|
||||
filter.keywords.any { keyword -> keyword.keyword.equals(tag.name, ignoreCase = true) }
|
||||
} ?: false
|
||||
}
|
||||
.sortedByDescending { tag -> tag.history.sumOf { it.uses.toLongOrNull() ?: 0 } }
|
||||
.toViewData()
|
||||
|
||||
val firstTag = tagResponse.first()
|
||||
val header = TrendingViewData.Header(firstTag.start(), firstTag.end())
|
||||
|
||||
_uiState.value = TrendingUiState(listOf(header) + tags, LoadingState.LOADED)
|
||||
},
|
||||
{ error ->
|
||||
Log.w(TAG, "failed loading trending tags", error)
|
||||
if (error is IOException) {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_NETWORK)
|
||||
} else {
|
||||
_uiState.value = TrendingUiState(emptyList(), LoadingState.ERROR_OTHER)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue