Library loading fixes

This commit is contained in:
Blatzar 2023-01-27 22:26:24 +01:00
parent 1f67644290
commit 7512dbcbf8
14 changed files with 254 additions and 121 deletions

View file

@ -569,7 +569,7 @@ class HomeFragment : Fragment() {
val mutableListOfResponse = mutableListOf<SearchResponse>()
listHomepageItems.clear()
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
(home_master_recycler?.adapter as? ParentItemAdapter)?.updateList(
d.values.toMutableList(),
home_master_recycler
)
@ -621,7 +621,7 @@ class HomeFragment : Fragment() {
//home_loaded?.isVisible = false
}
is Resource.Loading -> {
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(listOf())
(home_master_recycler?.adapter as? ParentItemAdapter)?.updateList(listOf())
home_loading_shimmer?.startShimmer()
home_loading?.isVisible = true
home_loading_error?.isVisible = false

View file

@ -2,13 +2,18 @@ package com.lagradost.cloudstream3.ui.library
import android.app.Activity
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.annotation.StringRes
import androidx.appcompat.widget.SearchView
import androidx.core.os.postDelayed
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import com.google.android.material.tabs.TabLayoutMediator
@ -20,6 +25,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.debugAssert
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.SyncIdName
@ -32,7 +38,9 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
import com.lagradost.cloudstream3.utils.AppUtils.reduceDragSensitivity
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import kotlinx.android.synthetic.main.fragment_library.*
import kotlinx.coroutines.delay
const val LIBRARY_FOLDER = "library_folder"
@ -285,9 +293,27 @@ class LibraryFragment : Fragment() {
viewpager?.offscreenPageLimit = 2
viewpager?.reduceDragSensitivity()
val startLoading = Runnable {
gridview?.numColumns = context?.getSpanCount() ?: 3
gridview?.adapter =
context?.let { LoadingPosterAdapter(it, 6 * 3) }
library_loading_overlay?.isVisible = true
library_loading_shimmer?.startShimmer()
empty_list_textview?.isVisible = false
}
val stopLoading = Runnable {
gridview?.adapter = null
library_loading_overlay?.isVisible = false
library_loading_shimmer?.stopShimmer()
}
val handler = Handler(Looper.getMainLooper())
observe(libraryViewModel.pages) { resource ->
when (resource) {
is Resource.Success -> {
handler.removeCallbacks(startLoading)
val pages = resource.value
val showNotice = pages.all { it.items.isEmpty() }
empty_list_textview?.isVisible = showNotice
@ -303,6 +329,11 @@ class LibraryFragment : Fragment() {
// Using notifyItemRangeChanged keeps the animations when sorting
viewpager.adapter?.notifyItemRangeChanged(0, viewpager.adapter?.itemCount ?: 0)
// Only stop loading after 300ms to hide the fade effect the viewpager produces when updating
// Without this there would be a flashing effect:
// loading -> show old viewpager -> black screen -> show new viewpager
handler.postDelayed(stopLoading, 300)
savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->
viewpager?.setCurrentItem(currentPos, false)
savedInstanceState.remove(VIEWPAGER_ITEM_KEY)
@ -314,20 +345,23 @@ class LibraryFragment : Fragment() {
) { tab, position ->
tab.text = pages.getOrNull(position)?.title?.asStringNull(context)
}.attach()
loading_indicator?.hide()
}
is Resource.Loading -> {
loading_indicator?.show()
empty_list_textview?.isVisible = false
// Only start loading after 200ms to prevent loading cached lists
handler.postDelayed(startLoading, 200)
}
is Resource.Failure -> {
stopLoading.run()
// No user indication it failed :(
// TODO
loading_indicator?.hide()
}
}
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
}
}
class MenuSearchView(context: Context) : SearchView(context) {

View file

@ -11,6 +11,7 @@ import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import kotlinx.coroutines.delay
enum class ListSorting(@StringRes val stringRes: Int) {
Query(R.string.none),
@ -96,6 +97,7 @@ class LibraryViewModel : ViewModel() {
)
}
delay(5000)
_pages.postValue(Resource.Success(pages))
}
}

View file

@ -0,0 +1,37 @@
package com.lagradost.cloudstream3.ui.library
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.ListPopupWindow.MATCH_PARENT
import android.widget.RelativeLayout
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.loading_poster_dynamic.view.*
import kotlin.math.roundToInt
import kotlin.math.sqrt
class LoadingPosterAdapter(context: Context, private val itemCount: Int) :
BaseAdapter() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
override fun getCount(): Int {
return itemCount
}
override fun getItem(position: Int): Any? {
return null
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
return convertView ?: inflater.inflate(R.layout.loading_poster_dynamic, parent, false)
}
}

View file

@ -220,7 +220,7 @@ class QuickSearchFragment : Fragment() {
when (it) {
is Resource.Success -> {
it.value.let { data ->
(quick_search_autofit_results?.adapter as? SearchAdapter?)?.updateList(
(quick_search_autofit_results?.adapter as? SearchAdapter)?.updateList(
context?.filterSearchResultByFilmQuality(data) ?: data
)
}

View file

@ -277,7 +277,7 @@ open class ResultFragment : ResultTrailerPlayer() {
private var downloadButton: EasyDownloadButton? = null
override fun onDestroyView() {
updateUIListener = null
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
(result_episodes?.adapter as? EpisodeAdapter)?.killAdapter()
downloadButton?.dispose()
super.onDestroyView()
@ -458,7 +458,7 @@ open class ResultFragment : ResultTrailerPlayer() {
temporary_no_focus?.requestFocus()
}
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
(result_episodes?.adapter as? EpisodeAdapter)?.updateList(episodes.value)
if (isTv && hasEpisodes) main {
delay(500)
@ -687,7 +687,7 @@ open class ResultFragment : ResultTrailerPlayer() {
val newList = list.filter { it.isSynced && it.hasAccount }
result_mini_sync?.isVisible = newList.isNotEmpty()
(result_mini_sync?.adapter as? ImageAdapter?)?.updateList(newList.mapNotNull { it.icon })
(result_mini_sync?.adapter as? ImageAdapter)?.updateList(newList.mapNotNull { it.icon })
}
var currentSyncProgress = 0
@ -900,7 +900,7 @@ open class ResultFragment : ResultTrailerPlayer() {
result_cast_items?.isVisible = d.actors != null
(result_cast_items?.adapter as ActorAdaptor?)?.apply {
(result_cast_items?.adapter as? ActorAdaptor)?.apply {
updateList(d.actors ?: emptyList())
}

View file

@ -485,7 +485,7 @@ class ResultFragmentPhone : ResultFragment() {
result_recommendations?.post {
rec?.let { list ->
(result_recommendations?.adapter as SearchAdapter?)?.updateList(list.filter { it.apiName == matchAgainst })
(result_recommendations?.adapter as? SearchAdapter)?.updateList(list.filter { it.apiName == matchAgainst })
}
}
}

View file

@ -107,7 +107,7 @@ class ResultFragmentTv : ResultFragment() {
result_recommendations?.isGone = isInvalid
result_recommendations_holder?.isGone = isInvalid
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
(result_recommendations?.adapter as SearchAdapter?)?.updateList(rec?.filter { it.apiName == matchAgainst }
(result_recommendations?.adapter as? SearchAdapter)?.updateList(rec?.filter { it.apiName == matchAgainst }
?: emptyList())
rec?.map { it.apiName }?.distinct()?.let { apiNames ->

View file

@ -420,7 +420,7 @@ class SearchFragment : Fragment() {
is Resource.Success -> {
it.value.let { data ->
if (data.isNotEmpty()) {
(search_autofit_results?.adapter as SearchAdapter?)?.updateList(data)
(search_autofit_results?.adapter as? SearchAdapter)?.updateList(data)
}
}
searchExitIcon.alpha = 1f

View file

@ -143,7 +143,7 @@ class PluginsFragment : Fragment() {
}
observe(pluginViewModel.filteredPlugins) { (scrollToTop, list) ->
(plugin_recycler_view?.adapter as? PluginAdapter?)?.updateList(list)
(plugin_recycler_view?.adapter as? PluginAdapter)?.updateList(list)
if (scrollToTop)
plugin_recycler_view?.scrollToPosition(0)

View file

@ -89,23 +89,53 @@
</com.google.android.material.appbar.AppBarLayout>
<!-- <RelativeLayout-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:nestedScrollingEnabled="true"-->
<!-- android:orientation="vertical"-->
<!-- app:layout_behavior="@string/appbar_scrolling_view_behavior">-->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="40dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/library_viewpager_page">
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</androidx.viewpager2.widget.ViewPager2>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="40dp"
tools:listitem="@layout/library_viewpager_page" />
<LinearLayout
android:visibility="gone"
android:id="@+id/library_loading_overlay"
android:layout_width="match_parent"
tools:visibility="visible"
android:layout_height="match_parent"
android:background="?attr/primaryBlackBackground">
<com.facebook.shimmer.ShimmerFrameLayout
android:layout_margin="2dp"
android:id="@+id/library_loading_shimmer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:elevation="100dp"
android:orientation="vertical"
app:shimmer_auto_start="true"
app:shimmer_base_alpha="0.2"
app:shimmer_duration="@integer/loading_time"
app:shimmer_highlight_alpha="0.3">
<GridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:numColumns="3"
tools:listitem="@layout/loading_poster_dynamic" />
</com.facebook.shimmer.ShimmerFrameLayout>
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
@ -115,28 +145,12 @@
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/sort_fab"
style="@style/ExtendedFloatingActionButton"
android:text="Sort"
android:text="@string/sort"
android:textColor="?attr/textColor"
app:icon="@drawable/ic_baseline_sort_24"
tools:ignore="ContentDescription" />
</FrameLayout>
<!-- </com.google.android.material.appbar.AppBarLayout>-->
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/loading_indicator"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="33dp"
android:elevation="100dp"
android:indeterminate="true"
android:indeterminateTint="?attr/colorPrimary"
android:progressTint="?attr/colorPrimary">
</androidx.core.widget.ContentLoadingProgressBar>
<com.google.android.material.tabs.TabLayout
android:id="@+id/library_tab_layout"
style="@style/Theme.Widget.Tabs"
@ -157,6 +171,5 @@
app:tabSelectedTextColor="@color/lightTextColor"
app:tabTextAppearance="@style/TabNoCaps"
app:tabTextColor="@color/textColor" />
<!-- </RelativeLayout>-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="10dp"
android:background="@color/grayShimmer"
app:cardCornerRadius="@dimen/loading_radius"
app:layout_constraintDimensionRatio="1:1.414"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include
layout="@layout/loading_line_short_center"
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp" />
</LinearLayout>

View file

@ -10,95 +10,104 @@
android:foreground="@drawable/outline_drawable"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/background_card"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:layout_marginBottom="2dp"
android:elevation="10dp"
app:cardBackgroundColor="?attr/primaryGrayBackground"
app:cardCornerRadius="@dimen/rounded_image_radius">
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
<androidx.cardview.widget.CardView
android:id="@+id/background_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/search_poster_img_des"
android:duplicateParentState="true"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
android:layout_height="0dp"
android:layout_margin="2dp"
android:layout_marginBottom="2dp"
android:elevation="10dp"
app:cardBackgroundColor="?attr/primaryGrayBackground"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:layout_constraintDimensionRatio="1:1.414"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/text_quality"
style="@style/TypeButton" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/search_poster_img_des"
android:duplicateParentState="true"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
<TextView
android:id="@+id/text_is_dub"
style="@style/DubButton"
android:layout_gravity="end" />
android:id="@+id/text_quality"
style="@style/TypeButton" />
<TextView
android:id="@+id/text_is_sub"
style="@style/SubButton"
android:layout_gravity="end" />
<androidx.cardview.widget.CardView
android:id="@+id/text_rating_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/rounded_image_radius"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:visibility="gone"
tools:visibility="visible"
android:layout_margin="2dp"
android:elevation="0dp"
app:cardElevation="0dp"
android:backgroundTint="@color/ratingColorBg">
android:orientation="vertical">
<TextView
android:id="@+id/text_is_dub"
style="@style/DubButton"
android:layout_gravity="end" />
<TextView
android:id="@+id/text_is_sub"
style="@style/SubButton"
android:layout_gravity="end" />
<androidx.cardview.widget.CardView
android:id="@+id/text_rating_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_margin="2dp"
android:backgroundTint="@color/ratingColorBg"
android:elevation="0dp"
android:visibility="gone"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardElevation="0dp"
tools:visibility="visible">
<TextView
android:id="@+id/text_rating"
style="@style/SearchBox"
android:layout_margin="0dp"
android:minWidth="40dp"
android:textColor="@color/ratingColor"
tools:text="★ 7.7" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/text_flag"
style="@style/SearchBox"
android:minWidth="40dp"
android:layout_margin="0dp"
android:textColor="@color/ratingColor"
android:id="@+id/text_rating"
tools:text="★ 7.7" />
</androidx.cardview.widget.CardView>
android:layout_gravity="end"
android:background="@color/transparent"
android:textSize="20sp"
android:visibility="gone"
tools:text="🇸🇪"
tools:visibility="visible" />
</LinearLayout>
<TextView
android:id="@+id/text_flag"
style="@style/SearchBox"
android:layout_gravity="end"
android:background="@color/transparent"
android:textSize="20sp"
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/watchProgress"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_gravity="bottom"
android:layout_marginBottom="-1.5dp"
android:progressBackgroundTint="?attr/colorPrimary"
android:progressTint="?attr/colorPrimary"
android:visibility="gone"
tools:text="🇸🇪"
tools:progress="50"
tools:visibility="visible" />
</LinearLayout>
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/watchProgress"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_gravity="bottom"
android:layout_marginBottom="-1.5dp"
android:progressBackgroundTint="?attr/colorPrimary"
android:progressTint="?attr/colorPrimary"
android:visibility="gone"
tools:progress="50"
tools:visibility="visible" />
</androidx.cardview.widget.CardView>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/imageText"

View file

@ -619,6 +619,7 @@
<string name="apk_installer_package_installer">PackageInstaller</string>
<string name="delayed_update_notice">App will be updated upon exit</string>
<string name="sort_by">Sort by</string>
<string name="sort">Sort</string>
<string name="sort_rating_desc">Rating (High to Low)</string>
<string name="sort_rating_asc">Rating (Low to High)</string>
<string name="sort_updated_new">Updated (New to Old)</string>