More work on local list support

This commit is contained in:
Blatzar 2023-01-21 14:21:36 +01:00
parent 7cd6dd3fe6
commit 019e9a0c4f
11 changed files with 143 additions and 109 deletions

View file

@ -1,7 +1,8 @@
package com.lagradost.cloudstream3.syncproviders package com.lagradost.cloudstream3.syncproviders
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.ui.library.LibraryItem import com.lagradost.cloudstream3.ui.library.ListSorting
import me.xdrop.fuzzywuzzy.FuzzySearch
enum class SyncIdName { enum class SyncIdName {
Anilist, Anilist,
@ -37,9 +38,9 @@ interface SyncAPI : OAuth2API {
suspend fun search(name: String): List<SyncSearchResult>? suspend fun search(name: String): List<SyncSearchResult>?
suspend fun getPersonalLibrary(): List<LibraryItem>? suspend fun getPersonalLibrary(): LibraryMetadata?
fun getIdFromUrl(url : String) : String fun getIdFromUrl(url: String): String
data class SyncSearchResult( data class SyncSearchResult(
override val name: String, override val name: String,
@ -59,7 +60,7 @@ interface SyncAPI : OAuth2API {
val score: Int?, val score: Int?,
val watchedEpisodes: Int?, val watchedEpisodes: Int?,
var isFavorite: Boolean? = null, var isFavorite: Boolean? = null,
var maxEpisodes : Int? = null, var maxEpisodes: Int? = null,
) )
data class SyncResult( data class SyncResult(
@ -80,9 +81,9 @@ interface SyncAPI : OAuth2API {
var genres: List<String>? = null, var genres: List<String>? = null,
var synonyms: List<String>? = null, var synonyms: List<String>? = null,
var trailers: List<String>? = null, var trailers: List<String>? = null,
var isAdult : Boolean? = null, var isAdult: Boolean? = null,
var posterUrl: String? = null, var posterUrl: String? = null,
var backgroundPosterUrl : String? = null, var backgroundPosterUrl: String? = null,
/** In unixtime */ /** In unixtime */
var startDate: Long? = null, var startDate: Long? = null,
@ -93,4 +94,53 @@ interface SyncAPI : OAuth2API {
var prevSeason: SyncSearchResult? = null, var prevSeason: SyncSearchResult? = null,
var actors: List<ActorData>? = null, var actors: List<ActorData>? = null,
) )
data class Page(
val title: String, var items: List<LibraryItem>
) {
fun sort(method: ListSorting?, query: String? = null) {
items = when (method) {
ListSorting.Query ->
if (query != null) {
items.sortedBy {
-FuzzySearch.partialRatio(
query.lowercase(), it.name.lowercase()
)
}
} else items
ListSorting.RatingHigh -> items.sortedBy { -(it.personalRating ?: 0) }
ListSorting.RatingLow -> items.sortedBy { (it.personalRating ?: 0) }
ListSorting.AlphabeticalA -> items.sortedBy { it.name }
ListSorting.AlphabeticalZ -> items.sortedBy { it.name }.reversed()
else -> items
}
}
}
data class LibraryMetadata(
/** List of all available pages, useful to show empty pages
* if the user has no entry on that page */
val allListNames: List<String>,
/** Not necessarily sorted list of all library items, will be grouped by listName */
val allLibraryItems: List<LibraryItem>
)
data class LibraryItem(
override val name: String,
override val url: String,
/** Unique unchanging string used for data storage */
val syncId: String,
val listName: String,
val episodesCompleted: Int?,
val episodesTotal: Int?,
/** Out of 100 */
val personalRating: Int?,
override val apiName: String,
override var type: TvType?,
override var posterUrl: String?,
override var posterHeaders: Map<String, String>?,
override var quality: SearchQuality?,
override var id: Int? = null,
) : SearchResponse
} }

View file

@ -4,7 +4,6 @@ import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.ui.library.LibraryItem
class SyncRepo(private val repo: SyncAPI) { class SyncRepo(private val repo: SyncAPI) {
val idPrefix = repo.idPrefix val idPrefix = repo.idPrefix
@ -30,7 +29,7 @@ class SyncRepo(private val repo: SyncAPI) {
return safeApiCall { repo.search(query) ?: throw ErrorLoadingException() } return safeApiCall { repo.search(query) ?: throw ErrorLoadingException() }
} }
suspend fun getPersonalLibrary(): Resource<List<LibraryItem>> { suspend fun getPersonalLibrary(): Resource<SyncAPI.LibraryMetadata> {
return safeApiCall { repo.getPersonalLibrary() ?: throw ErrorLoadingException() } return safeApiCall { repo.getPersonalLibrary() ?: throw ErrorLoadingException() }
} }

View file

@ -11,7 +11,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.AuthAPI import com.lagradost.cloudstream3.syncproviders.AuthAPI
import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.ui.library.LibraryItem
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.splitQuery import com.lagradost.cloudstream3.utils.AppUtils.splitQuery
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
@ -598,8 +597,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
@JsonProperty("private") val private: Boolean, @JsonProperty("private") val private: Boolean,
@JsonProperty("media") val media: Media @JsonProperty("media") val media: Media
) { ) {
fun toLibraryItem(listName: String?): LibraryItem? { fun toLibraryItem(listName: String?): SyncAPI.LibraryItem? {
return LibraryItem( return SyncAPI.LibraryItem(
// English title first // English title first
this.media.title.english ?: this.media.title.romaji this.media.title.english ?: this.media.title.romaji
?: this.media.synonyms.firstOrNull() ?: this.media.synonyms.firstOrNull()
@ -612,7 +611,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
this.score, this.score,
"AniList", "AniList",
TvType.Anime, TvType.Anime,
this.media.coverImage.extraLarge ?: this.media.coverImage.large ?: this.media.coverImage.medium, this.media.coverImage.extraLarge ?: this.media.coverImage.large
?: this.media.coverImage.medium,
null, null,
null, null,
null null
@ -653,14 +653,17 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
} }
} }
override suspend fun getPersonalLibrary(): List<LibraryItem>? { override suspend fun getPersonalLibrary(): SyncAPI.LibraryMetadata {
return getAniListAnimeListSmart()?.map { return SyncAPI.LibraryMetadata(
it.entries.mapNotNull { entry -> emptyList(),
entry.toLibraryItem( getAniListAnimeListSmart()?.map {
entry.status ?: it.status it.entries.mapNotNull { entry ->
) entry.toLibraryItem(
} entry.status ?: it.status
}?.flatten() )
}
}?.flatten() ?: emptyList()
)
} }
private suspend fun getFullAniListList(): FullAnilistList? { private suspend fun getFullAniListList(): FullAnilistList? {

View file

@ -1,10 +1,12 @@
package com.lagradost.cloudstream3.syncproviders.providers package com.lagradost.cloudstream3.syncproviders.providers
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.syncproviders.AuthAPI import com.lagradost.cloudstream3.syncproviders.AuthAPI
import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.ui.library.LibraryItem import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.utils.Coroutines.ioWork import com.lagradost.cloudstream3.utils.Coroutines.ioWork
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
@ -17,8 +19,12 @@ class LocalList : SyncAPI {
override val createAccountUrl: Nothing? = null override val createAccountUrl: Nothing? = null
override val idPrefix = "local" override val idPrefix = "local"
override fun loginInfo(): AuthAPI.LoginInfo? { override fun loginInfo(): AuthAPI.LoginInfo {
return null return AuthAPI.LoginInfo(
null,
null,
0
)
} }
override fun logOut() { override fun logOut() {
@ -52,18 +58,29 @@ class LocalList : SyncAPI {
return null return null
} }
override suspend fun getPersonalLibrary(): List<LibraryItem> { override suspend fun getPersonalLibrary(): SyncAPI.LibraryMetadata? {
val watchStatusIds = ioWork { val watchStatusIds = ioWork {
getAllWatchStateIds()?.map { id -> getAllWatchStateIds()?.map { id ->
Pair(id, getResultWatchState(id)) Pair(id, getResultWatchState(id))
} }
}?.distinctBy { it.first } ?: return emptyList() }?.distinctBy { it.first } ?: return null
return ioWork { val list = ioWork {
watchStatusIds.mapNotNull { watchStatusIds.mapNotNull {
getBookmarkedData(it.first)?.toLibraryItem(it.second) getBookmarkedData(it.first)?.toLibraryItem(it.second)
} }
} }
return SyncAPI.LibraryMetadata(
WatchType.values().mapNotNull {
// None is not something to display
if (it == WatchType.NONE) return@mapNotNull null
// Dirty hack for context!
txt(it.stringRes).asStringNull(AcraApplication.context)
},
list
)
} }
override fun getIdFromUrl(url: String): String { override fun getIdFromUrl(url: String): String {

View file

@ -14,7 +14,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.AuthAPI import com.lagradost.cloudstream3.syncproviders.AuthAPI
import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.ui.library.LibraryItem
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.splitQuery import com.lagradost.cloudstream3.utils.AppUtils.splitQuery
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
@ -386,8 +385,8 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
@JsonProperty("node") val node: Node, @JsonProperty("node") val node: Node,
@JsonProperty("list_status") val list_status: ListStatus?, @JsonProperty("list_status") val list_status: ListStatus?,
) { ) {
fun toLibraryItem(): LibraryItem { fun toLibraryItem(): SyncAPI.LibraryItem {
return LibraryItem( return SyncAPI.LibraryItem(
this.node.title, this.node.title,
"https://myanimelist.net/anime/${this.node.id}/", "https://myanimelist.net/anime/${this.node.id}/",
this.node.id.toString(), this.node.id.toString(),
@ -445,8 +444,11 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
} }
} }
override suspend fun getPersonalLibrary(): List<LibraryItem>? { override suspend fun getPersonalLibrary(): SyncAPI.LibraryMetadata {
return getMalAnimeListSmart()?.map { it.toLibraryItem() } return SyncAPI.LibraryMetadata(
emptyList(),
getMalAnimeListSmart()?.map { it.toLibraryItem() } ?: emptyList()
)
} }
private suspend fun getMalAnimeList(): Array<Data> { private suspend fun getMalAnimeList(): Array<Data> {

View file

@ -15,6 +15,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.debugAssert import com.lagradost.cloudstream3.mvvm.debugAssert
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.ui.result.txt import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
@ -126,7 +127,8 @@ class LibraryFragment : Fragment() {
// If provider // If provider
savedSelection.openType == LibraryOpenerType.Provider savedSelection.openType == LibraryOpenerType.Provider
&& savedSelection.providerData?.apiName != null -> { && savedSelection.providerData?.apiName != null -> {
availableProviders.indexOf(savedSelection.providerData.apiName).takeIf { it != -1 } availableProviders.indexOf(savedSelection.providerData.apiName)
.takeIf { it != -1 }
?.plus(baseOptions.size) ?: -1 ?.plus(baseOptions.size) ?: -1
} }
// Else base option // Else base option
@ -167,7 +169,7 @@ class LibraryFragment : Fragment() {
viewpager?.setPageTransformer(LibraryScrollTransformer()) viewpager?.setPageTransformer(LibraryScrollTransformer())
viewpager?.adapter = viewpager?.adapter =
viewpager.adapter ?: ViewpagerAdapter(emptyList(), { isScrollingDown: Boolean -> viewpager.adapter ?: ViewpagerAdapter(mutableListOf(), { isScrollingDown: Boolean ->
if (isScrollingDown) { if (isScrollingDown) {
sort_fab?.shrink() sort_fab?.shrink()
} else { } else {
@ -177,11 +179,11 @@ class LibraryFragment : Fragment() {
// To prevent future accidents // To prevent future accidents
debugAssert({ debugAssert({
searchClickCallback.card !is LibraryItem searchClickCallback.card !is SyncAPI.LibraryItem
}, { }, {
"searchClickCallback ${searchClickCallback.card} is not a LibraryItem" "searchClickCallback ${searchClickCallback.card} is not a LibraryItem"
}) })
val syncId = (searchClickCallback.card as LibraryItem).syncId val syncId = (searchClickCallback.card as SyncAPI.LibraryItem).syncId
println("SEARCH CLICK $searchClickCallback") println("SEARCH CLICK $searchClickCallback")
when (searchClickCallback.action) { when (searchClickCallback.action) {
@ -200,7 +202,8 @@ class LibraryFragment : Fragment() {
observe(libraryViewModel.pages) { pages -> observe(libraryViewModel.pages) { pages ->
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages (viewpager.adapter as? ViewpagerAdapter)?.pages = pages
viewpager.adapter?.notifyItemChanged(viewpager?.currentItem ?: 0) // Using notifyItemRangeChanged keeps the animations when sorting
viewpager.adapter?.notifyItemRangeChanged(0, viewpager.adapter?.itemCount ?: 0)
TabLayoutMediator( TabLayoutMediator(
library_tab_layout, library_tab_layout,

View file

@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
enum class ListSorting(@StringRes val stringRes: Int) { enum class ListSorting(@StringRes val stringRes: Int) {
@ -20,8 +21,8 @@ enum class ListSorting(@StringRes val stringRes: Int) {
} }
class LibraryViewModel : ViewModel() { class LibraryViewModel : ViewModel() {
private val _pages: MutableLiveData<List<Page>> = MutableLiveData(emptyList()) private val _pages: MutableLiveData<List<SyncAPI.Page>> = MutableLiveData(emptyList())
val pages: LiveData<List<Page>> = _pages val pages: LiveData<List<SyncAPI.Page>> = _pages
private val _currentApiName: MutableLiveData<String> = MutableLiveData("") private val _currentApiName: MutableLiveData<String> = MutableLiveData("")
val currentApiName: LiveData<String> = _currentApiName val currentApiName: LiveData<String> = _currentApiName
@ -65,15 +66,22 @@ class LibraryViewModel : ViewModel() {
fun loadPages() { fun loadPages() {
ioSafe { ioSafe {
currentSyncApi?.let { repo -> currentSyncApi?.let { repo ->
val list = (repo.getPersonalLibrary() as? Resource.Success)?.value _currentApiName.postValue(repo.name)
val pages = (list ?: emptyList()).groupBy { it.listName }.map { val library = (repo.getPersonalLibrary() as? Resource.Success)?.value ?: return@let
Page(
val listSubset = library.allLibraryItems.groupBy { it.listName }
val allLists = library.allListNames.associateWith { emptyList<SyncAPI.LibraryItem>() }
val filledLists = allLists + listSubset
val pages = filledLists.map {
SyncAPI.Page(
it.key, it.key,
it.value it.value
) )
} }
println("PAGES $pages")
_pages.postValue(pages) _pages.postValue(pages)
_currentApiName.postValue(repo.name)
} }
} }
} }

View file

@ -6,16 +6,17 @@ import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.ui.search.SearchClickCallback import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils
import kotlinx.android.synthetic.main.search_result_grid_expanded.view.* import kotlinx.android.synthetic.main.search_result_grid_expanded.view.*
class PageAdapter( class PageAdapter(
override val items: MutableList<LibraryItem>, override val items: MutableList<SyncAPI.LibraryItem>,
val clickCallback: (SearchClickCallback) -> Unit val clickCallback: (SearchClickCallback) -> Unit
) : ) :
AppUtils.DiffAdapter<LibraryItem>(items) { AppUtils.DiffAdapter<SyncAPI.LibraryItem>(items) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return LibraryItemViewHolder( return LibraryItemViewHolder(
@ -33,7 +34,7 @@ class PageAdapter(
} }
inner class LibraryItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class LibraryItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: LibraryItem, position: Int) { fun bind(item: SyncAPI.LibraryItem, position: Int) {
SearchResultBuilder.bind( SearchResultBuilder.bind(
this@PageAdapter.clickCallback, this@PageAdapter.clickCallback,
item, item,

View file

@ -4,62 +4,16 @@ import android.os.Build
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnFlingListener import androidx.recyclerview.widget.RecyclerView.OnFlingListener
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchQuality import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.ui.search.SearchClickCallback import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import kotlinx.android.synthetic.main.library_viewpager_page.view.* import kotlinx.android.synthetic.main.library_viewpager_page.view.*
import me.xdrop.fuzzywuzzy.FuzzySearch
data class Page(
val title: String, var items: List<LibraryItem>
) {
fun sort(method: ListSorting?, query: String? = null) {
items = when (method) {
ListSorting.Query ->
if (query != null) {
items.sortedBy {
-FuzzySearch.partialRatio(
query.lowercase(), it.name.lowercase()
)
}
} else items
ListSorting.RatingHigh -> items.sortedBy { -(it.personalRating ?: 0) }
ListSorting.RatingLow -> items.sortedBy { (it.personalRating ?: 0) }
ListSorting.AlphabeticalA -> items.sortedBy { it.name }
ListSorting.AlphabeticalZ -> items.sortedBy { it.name }.reversed()
else -> items
}
}
}
data class LibraryItem(
override val name: String,
override val url: String,
/** Unique unchanging string used for data storage */
val syncId: String,
val listName: String,
val episodesCompleted: Int?,
val episodesTotal: Int?,
/** Out of 100 */
val personalRating: Int?,
override val apiName: String,
override var type: TvType?,
override var posterUrl: String?,
override var posterHeaders: Map<String, String>?,
override var quality: SearchQuality?,
override var id: Int? = null,
) : SearchResponse
class ViewpagerAdapter( class ViewpagerAdapter(
var pages: List<Page>, var pages: List<SyncAPI.Page>,
val scrollCallback: (isScrollingDown: Boolean) -> Unit, val scrollCallback: (isScrollingDown: Boolean) -> Unit,
val clickCallback: (SearchClickCallback) -> Unit val clickCallback: (SearchClickCallback) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
@ -80,7 +34,7 @@ class ViewpagerAdapter(
inner class PageViewHolder(private val itemViewTest: View) : inner class PageViewHolder(private val itemViewTest: View) :
RecyclerView.ViewHolder(itemViewTest) { RecyclerView.ViewHolder(itemViewTest) {
fun bind(page: Page) { fun bind(page: SyncAPI.Page) {
if (itemViewTest.page_recyclerview?.adapter == null) { if (itemViewTest.page_recyclerview?.adapter == null) {
itemViewTest.page_recyclerview?.adapter = PageAdapter(page.items.toMutableList(), clickCallback) itemViewTest.page_recyclerview?.adapter = PageAdapter(page.items.toMutableList(), clickCallback)
itemView.page_recyclerview?.spanCount = itemView.page_recyclerview?.spanCount =

View file

@ -277,18 +277,14 @@ object AppUtils {
} }
fun updateList(newList: List<T>) { fun updateList(newList: List<T>) {
val time = measureTimeMillis { val diffResult = DiffUtil.calculateDiff(
GenericDiffCallback(this.items, newList)
)
val diffResult = DiffUtil.calculateDiff( items.clear()
GenericDiffCallback(this.items, newList) items.addAll(newList)
)
items.clear() diffResult.dispatchUpdatesTo(this)
items.addAll(newList)
diffResult.dispatchUpdatesTo(this)
}
println("TIME TAKEn $time")
} }
inner class GenericDiffCallback( inner class GenericDiffCallback(

View file

@ -11,10 +11,8 @@ import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.SearchQuality import com.lagradost.cloudstream3.SearchQuality
import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.providers.LocalList
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.library.LibraryItem
const val VIDEO_POS_DUR = "video_pos_dur" const val VIDEO_POS_DUR = "video_pos_dur"
const val RESULT_WATCH_STATE = "result_watch_state" const val RESULT_WATCH_STATE = "result_watch_state"
@ -54,8 +52,8 @@ object DataStoreHelper {
@JsonProperty("quality") override var quality: SearchQuality? = null, @JsonProperty("quality") override var quality: SearchQuality? = null,
@JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null, @JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null,
) : SearchResponse { ) : SearchResponse {
fun toLibraryItem(state: WatchType): LibraryItem { fun toLibraryItem(state: WatchType): SyncAPI.LibraryItem {
return LibraryItem( return SyncAPI.LibraryItem(
name, name,
url, url,
url, url,
@ -86,6 +84,9 @@ object DataStoreHelper {
@JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null, @JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null,
) : SearchResponse ) : SearchResponse
/**
* A datastore wide account for future implementations of a multiple account system
**/
private var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION private var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
fun getAllWatchStateIds(): List<Int>? { fun getAllWatchStateIds(): List<Int>? {