Add list switcher

This commit is contained in:
Blatzar 2022-12-18 19:22:35 +01:00
parent 67a1c447ae
commit 2a2a0a26e7
4 changed files with 71 additions and 36 deletions

View file

@ -1,12 +1,9 @@
package com.lagradost.cloudstream3.syncproviders.providers package com.lagradost.cloudstream3.syncproviders.providers
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.capitalize
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -141,7 +138,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
this.name, this.name,
recMedia.id?.toString() ?: return@mapNotNull null, recMedia.id?.toString() ?: return@mapNotNull null,
getUrlFromId(recMedia.id), getUrlFromId(recMedia.id),
recMedia.coverImage?.large ?: recMedia.coverImage?.medium recMedia.coverImage?.extraLarge ?: recMedia.coverImage?.large
?: recMedia.coverImage?.medium
) )
}, },
trailers = when (season.trailer?.site?.lowercase()?.trim()) { trailers = when (season.trailer?.site?.lowercase()?.trim()) {
@ -220,7 +218,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
romaji romaji
} }
idMal idMal
coverImage { medium large } coverImage { medium large extraLarge }
averageScore averageScore
} }
} }
@ -233,7 +231,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
format format
id id
idMal idMal
coverImage { medium large } coverImage { medium large extraLarge }
averageScore averageScore
title { title {
english english
@ -569,7 +567,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
data class CoverImage( data class CoverImage(
@JsonProperty("medium") val medium: String?, @JsonProperty("medium") val medium: String?,
@JsonProperty("large") val large: String? @JsonProperty("large") val large: String?,
@JsonProperty("extraLarge") val extraLarge: String?
) )
data class Media( data class Media(
@ -600,16 +599,17 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
fun toLibraryItem(listName: String?): LibraryItem? { fun toLibraryItem(listName: String?): LibraryItem? {
return LibraryItem( return LibraryItem(
// English title first // English title first
this.media.title.english ?: this.media.title.romaji ?: this.media.synonyms.firstOrNull() this.media.title.english ?: this.media.title.romaji
?: this.media.synonyms.firstOrNull()
?: "", ?: "",
"https://anilist.co/anime/${this.media.id}/", "https://anilist.co/anime/${this.media.id}/",
listName ?: return null, listName?.lowercase()?.capitalize() ?: return null,
this.progress, this.progress,
this.media.episodes, this.media.episodes,
this.score, this.score,
"AniList", "AniList",
TvType.Anime, TvType.Anime,
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
@ -630,44 +630,44 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
@JsonProperty("MediaListCollection") val MediaListCollection: MediaListCollection @JsonProperty("MediaListCollection") val MediaListCollection: MediaListCollection
) )
fun getAnilistListCached(): Array<Lists>? { private fun getAniListListCached(): Array<Lists>? {
return getKey(ANILIST_CACHED_LIST) as? Array<Lists> return getKey(ANILIST_CACHED_LIST) as? Array<Lists>
} }
suspend fun getAnilistAnimeListSmart(): Array<Lists>? { private suspend fun getAniListAnimeListSmart(): Array<Lists>? {
if (getAuth() == null) return null if (getAuth() == null) return null
if (checkToken()) return null if (checkToken()) return null
return if (getKey(ANILIST_SHOULD_UPDATE_LIST, true) == true) { return if (getKey(ANILIST_SHOULD_UPDATE_LIST, true) == true) {
val list = getFullAnilistList()?.data?.MediaListCollection?.lists?.toTypedArray() val list = getFullAniListList()?.data?.MediaListCollection?.lists?.toTypedArray()
if (list != null) { if (list != null) {
setKey(ANILIST_CACHED_LIST, list) setKey(ANILIST_CACHED_LIST, list)
setKey(ANILIST_SHOULD_UPDATE_LIST, false) setKey(ANILIST_SHOULD_UPDATE_LIST, false)
} }
list list
} else { } else {
getAnilistListCached() getAniListListCached()
} }
} }
override suspend fun getPersonalLibrary(): List<LibraryItem>? { override suspend fun getPersonalLibrary(): List<LibraryItem>? {
return getAnilistAnimeListSmart()?.map { it.entries.mapNotNull { entry -> entry.toLibraryItem(entry.status ?: it.status) } }?.flatten() return getAniListAnimeListSmart()?.map {
it.entries.mapNotNull { entry ->
entry.toLibraryItem(
entry.status ?: it.status
)
}
}?.flatten()
} }
private suspend fun getFullAnilistList(): FullAnilistList? { private suspend fun getFullAniListList(): FullAnilistList? {
var userID: Int? = null
/** WARNING ASSUMES ONE USER! **/ /** WARNING ASSUMES ONE USER! **/
getKeys(ANILIST_USER_KEY)?.forEach { key ->
getKey<AniListUser>(key, null)?.let {
userID = it.id
}
}
val fixedUserID = userID ?: return null val userID = getKey<AniListUser>(accountId, ANILIST_USER_KEY)?.id ?: return null
val mediaType = "ANIME" val mediaType = "ANIME"
val query = """ val query = """
query (${'$'}userID: Int = $fixedUserID, ${'$'}MEDIA: MediaType = $mediaType) { query (${'$'}userID: Int = $userID, ${'$'}MEDIA: MediaType = $mediaType) {
MediaListCollection (userId: ${'$'}userID, type: ${'$'}MEDIA) { MediaListCollection (userId: ${'$'}userID, type: ${'$'}MEDIA) {
lists { lists {
status status
@ -694,7 +694,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
english english
romaji romaji
} }
coverImage { medium } coverImage { extraLarge large medium }
synonyms synonyms
nextAiringEpisode { nextAiringEpisode {
timeUntilAiring timeUntilAiring
@ -706,7 +706,9 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
} }
} }
""" """
val text = postApi(query) val text = postApi(query).also {
println("REPONSE $it")
}
return text?.toKotlinObject() return text?.toKotlinObject()
} }

View file

@ -68,6 +68,22 @@ class LibraryFragment : Fragment() {
libraryViewModel.loadPages() libraryViewModel.loadPages()
list_selector?.setOnClickListener {
val items = libraryViewModel.availableApiNames
val currentItem = libraryViewModel.currentApiName.value
activity?.showBottomDialog(
items,
items.indexOf(currentItem),
"Select library",
false,
{}
) {
val selectedItem = items.getOrNull(it) ?: return@showBottomDialog
libraryViewModel.switchList(selectedItem)
}
}
viewpager?.setPageTransformer(LibraryScrollTransformer()) viewpager?.setPageTransformer(LibraryScrollTransformer())
viewpager?.adapter = viewpager?.adapter =
viewpager.adapter ?: ViewpagerAdapter(emptyList(), { isScrollingDown: Boolean -> viewpager.adapter ?: ViewpagerAdapter(emptyList(), { isScrollingDown: Boolean ->

View file

@ -8,7 +8,6 @@ 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.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import me.xdrop.fuzzywuzzy.FuzzySearch
enum class ListSorting(@StringRes val stringRes: Int) { enum class ListSorting(@StringRes val stringRes: Int) {
Query(R.string.none), Query(R.string.none),
@ -27,8 +26,10 @@ class LibraryViewModel : ViewModel() {
private val _currentApiName: MutableLiveData<String> = MutableLiveData("") private val _currentApiName: MutableLiveData<String> = MutableLiveData("")
val currentApiName: LiveData<String> = _currentApiName val currentApiName: LiveData<String> = _currentApiName
private val listApis = SyncApis.filter { it.hasAccount() } private val availableSyncApis = SyncApis.filter { it.hasAccount() }
private var currentApi = listApis.firstOrNull() private var currentSyncApi = availableSyncApis.firstOrNull()
val availableApiNames: List<String> = availableSyncApis.map { it.name }
val sortingMethods = listOf( val sortingMethods = listOf(
ListSorting.RatingHigh, ListSorting.RatingHigh,
@ -42,8 +43,10 @@ class LibraryViewModel : ViewModel() {
var currentSortingMethod: ListSorting = sortingMethods.first() var currentSortingMethod: ListSorting = sortingMethods.first()
private set private set
fun switchList() { fun switchList(name: String) {
currentApi = listApis[(listApis.indexOf(currentApi) + 1) % listApis.size] currentSyncApi = availableSyncApis[availableApiNames.indexOf(name)]
_currentApiName.postValue(currentSyncApi?.name)
loadPages() loadPages()
} }
@ -58,7 +61,7 @@ class LibraryViewModel : ViewModel() {
fun loadPages() { fun loadPages() {
ioSafe { ioSafe {
currentApi?.let { repo -> currentSyncApi?.let { repo ->
val list = (repo.getPersonalLibrary() as? Resource.Success)?.value val list = (repo.getPersonalLibrary() as? Resource.Success)?.value
val pages = (list ?: emptyList()).groupBy { it.listName }.map { val pages = (list ?: emptyList()).groupBy { it.listName }.map {
Page( Page(

View file

@ -34,8 +34,6 @@
android:nextFocusLeft="@id/nav_rail_view" android:nextFocusLeft="@id/nav_rail_view"
android:nextFocusRight="@id/search_filter" android:nextFocusRight="@id/search_filter"
android:nextFocusUp="@id/nav_rail_view"
android:nextFocusDown="@id/search_autofit_results"
android:paddingStart="-10dp" android:paddingStart="-10dp"
app:iconifiedByDefault="false" app:iconifiedByDefault="false"
app:queryBackground="@color/transparent" app:queryBackground="@color/transparent"
@ -44,6 +42,22 @@
tools:ignore="RtlSymmetry"> tools:ignore="RtlSymmetry">
</androidx.appcompat.widget.SearchView> </androidx.appcompat.widget.SearchView>
<ImageView
android:id="@+id/list_selector"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="end|center_vertical"
android:layout_margin="10dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/change_providers_img_des"
android:nextFocusLeft="@id/main_search"
android:nextFocusRight="@id/main_search"
android:src="@drawable/ic_baseline_filter_list_24"
app:tint="?attr/textColor" />
</FrameLayout> </FrameLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -76,7 +90,7 @@
style="@style/ExtendedFloatingActionButton" style="@style/ExtendedFloatingActionButton"
android:text="Sort" android:text="Sort"
android:textColor="?attr/textColor" android:textColor="?attr/textColor"
app:icon="@drawable/ic_baseline_filter_list_24" app:icon="@drawable/ic_baseline_sort_24"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</FrameLayout> </FrameLayout>