forked from recloudstream/cloudstream
Added visible loading in library and fix reloading on sync
This commit is contained in:
parent
f6c609cfdf
commit
dd293e9564
6 changed files with 58 additions and 33 deletions
|
@ -68,7 +68,6 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
switchToNewAccount()
|
switchToNewAccount()
|
||||||
setKey(accountId, ANILIST_UNIXTIME_KEY, endTime)
|
setKey(accountId, ANILIST_UNIXTIME_KEY, endTime)
|
||||||
setKey(accountId, ANILIST_TOKEN_KEY, token)
|
setKey(accountId, ANILIST_TOKEN_KEY, token)
|
||||||
setKey(ANILIST_SHOULD_UPDATE_LIST, true)
|
|
||||||
val user = getUser()
|
val user = getUser()
|
||||||
requireLibraryRefresh = true
|
requireLibraryRefresh = true
|
||||||
return user != null
|
return user != null
|
||||||
|
@ -189,7 +188,6 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
const val ANILIST_TOKEN_KEY: String = "anilist_token" // anilist token for api
|
const val ANILIST_TOKEN_KEY: String = "anilist_token" // anilist token for api
|
||||||
const val ANILIST_USER_KEY: String = "anilist_user" // user data like profile
|
const val ANILIST_USER_KEY: String = "anilist_user" // user data like profile
|
||||||
const val ANILIST_CACHED_LIST: String = "anilist_cached_list"
|
const val ANILIST_CACHED_LIST: String = "anilist_cached_list"
|
||||||
const val ANILIST_SHOULD_UPDATE_LIST: String = "anilist_should_update_list"
|
|
||||||
|
|
||||||
private fun fixName(name: String): String {
|
private fun fixName(name: String): String {
|
||||||
return name.lowercase(Locale.ROOT).replace(" ", "")
|
return name.lowercase(Locale.ROOT).replace(" ", "")
|
||||||
|
@ -655,11 +653,10 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
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 (requireLibraryRefresh) {
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
list
|
list
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -254,7 +254,6 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
|
|
||||||
const val MAL_USER_KEY: String = "mal_user" // user data like profile
|
const val MAL_USER_KEY: String = "mal_user" // user data like profile
|
||||||
const val MAL_CACHED_LIST: String = "mal_cached_list"
|
const val MAL_CACHED_LIST: String = "mal_cached_list"
|
||||||
const val MAL_SHOULD_UPDATE_LIST: String = "mal_should_update_list"
|
|
||||||
const val MAL_UNIXTIME_KEY: String = "mal_unixtime" // When token expires
|
const val MAL_UNIXTIME_KEY: String = "mal_unixtime" // When token expires
|
||||||
const val MAL_REFRESH_TOKEN_KEY: String = "mal_refresh_token" // refresh token
|
const val MAL_REFRESH_TOKEN_KEY: String = "mal_refresh_token" // refresh token
|
||||||
const val MAL_TOKEN_KEY: String = "mal_token" // anilist token for api
|
const val MAL_TOKEN_KEY: String = "mal_token" // anilist token for api
|
||||||
|
@ -281,7 +280,7 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
switchToNewAccount()
|
switchToNewAccount()
|
||||||
storeToken(res)
|
storeToken(res)
|
||||||
val user = getMalUser()
|
val user = getMalUser()
|
||||||
setKey(MAL_SHOULD_UPDATE_LIST, true)
|
requireLibraryRefresh = true
|
||||||
return user != null
|
return user != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,10 +438,9 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
|
|
||||||
private suspend fun getMalAnimeListSmart(): Array<Data>? {
|
private suspend fun getMalAnimeListSmart(): Array<Data>? {
|
||||||
if (getAuth() == null) return null
|
if (getAuth() == null) return null
|
||||||
return if (getKey(MAL_SHOULD_UPDATE_LIST, true) == true) {
|
return if (requireLibraryRefresh) {
|
||||||
val list = getMalAnimeList()
|
val list = getMalAnimeList()
|
||||||
setKey(MAL_CACHED_LIST, list)
|
setKey(MAL_CACHED_LIST, list)
|
||||||
setKey(MAL_SHOULD_UPDATE_LIST, false)
|
|
||||||
list
|
list
|
||||||
} else {
|
} else {
|
||||||
getMalAnimeListCached()
|
getMalAnimeListCached()
|
||||||
|
|
|
@ -18,6 +18,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
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.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
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.SyncAPI
|
||||||
|
@ -278,24 +279,37 @@ class LibraryFragment : Fragment() {
|
||||||
viewpager?.offscreenPageLimit = 2
|
viewpager?.offscreenPageLimit = 2
|
||||||
viewpager?.reduceDragSensitivity()
|
viewpager?.reduceDragSensitivity()
|
||||||
|
|
||||||
observe(libraryViewModel.pages) { pages ->
|
observe(libraryViewModel.pages) { resource ->
|
||||||
empty_list_textview?.isVisible = pages.all { it.items.isEmpty() }
|
when (resource) {
|
||||||
|
is Resource.Success -> {
|
||||||
|
val pages = resource.value
|
||||||
|
empty_list_textview?.isVisible = pages.all { it.items.isEmpty() }
|
||||||
|
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages
|
||||||
|
// Using notifyItemRangeChanged keeps the animations when sorting
|
||||||
|
viewpager.adapter?.notifyItemRangeChanged(0, viewpager.adapter?.itemCount ?: 0)
|
||||||
|
|
||||||
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages
|
savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->
|
||||||
// Using notifyItemRangeChanged keeps the animations when sorting
|
viewpager?.setCurrentItem(currentPos, false)
|
||||||
viewpager.adapter?.notifyItemRangeChanged(0, viewpager.adapter?.itemCount ?: 0)
|
savedInstanceState.remove(VIEWPAGER_ITEM_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->
|
TabLayoutMediator(
|
||||||
viewpager?.setCurrentItem(currentPos, false)
|
library_tab_layout,
|
||||||
savedInstanceState.remove(VIEWPAGER_ITEM_KEY)
|
viewpager,
|
||||||
|
) { tab, position ->
|
||||||
|
tab.text = pages.getOrNull(position)?.title
|
||||||
|
}.attach()
|
||||||
|
loading_indicator?.hide()
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
loading_indicator?.show()
|
||||||
|
}
|
||||||
|
is Resource.Failure -> {
|
||||||
|
// No user indication it failed :(
|
||||||
|
// TODO
|
||||||
|
loading_indicator?.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TabLayoutMediator(
|
|
||||||
library_tab_layout,
|
|
||||||
viewpager,
|
|
||||||
) { tab, position ->
|
|
||||||
tab.text = pages.getOrNull(position)?.title
|
|
||||||
}.attach()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ enum class ListSorting(@StringRes val stringRes: Int) {
|
||||||
const val LAST_SYNC_API_KEY = "last_sync_api"
|
const val LAST_SYNC_API_KEY = "last_sync_api"
|
||||||
|
|
||||||
class LibraryViewModel : ViewModel() {
|
class LibraryViewModel : ViewModel() {
|
||||||
private val _pages: MutableLiveData<List<SyncAPI.Page>> = MutableLiveData(null)
|
private val _pages: MutableLiveData<Resource<List<SyncAPI.Page>>> = MutableLiveData(null)
|
||||||
val pages: LiveData<List<SyncAPI.Page>> = _pages
|
val pages: LiveData<Resource<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
|
||||||
|
@ -67,7 +67,7 @@ class LibraryViewModel : ViewModel() {
|
||||||
fun sort(method: ListSorting, query: String? = null) {
|
fun sort(method: ListSorting, query: String? = null) {
|
||||||
val currentList = pages.value ?: return
|
val currentList = pages.value ?: return
|
||||||
currentSortingMethod = method
|
currentSortingMethod = method
|
||||||
currentList.forEachIndexed { _, page ->
|
(currentList as? Resource.Success)?.value?.forEachIndexed { _, page ->
|
||||||
page.sort(method, query)
|
page.sort(method, query)
|
||||||
}
|
}
|
||||||
_pages.postValue(currentList)
|
_pages.postValue(currentList)
|
||||||
|
@ -75,14 +75,21 @@ class LibraryViewModel : ViewModel() {
|
||||||
|
|
||||||
fun reloadPages(forceReload: Boolean) {
|
fun reloadPages(forceReload: Boolean) {
|
||||||
// Only skip loading if its not forced and pages is not empty
|
// Only skip loading if its not forced and pages is not empty
|
||||||
if (!forceReload && pages.value?.isNotEmpty() == true &&
|
if (!forceReload && (pages.value as? Resource.Success)?.value?.isNotEmpty() == true &&
|
||||||
currentSyncApi?.requireLibraryRefresh != true
|
currentSyncApi?.requireLibraryRefresh != true
|
||||||
) return
|
) return
|
||||||
|
|
||||||
ioSafe {
|
ioSafe {
|
||||||
currentSyncApi?.let { repo ->
|
currentSyncApi?.let { repo ->
|
||||||
_currentApiName.postValue(repo.name)
|
_currentApiName.postValue(repo.name)
|
||||||
val library = (repo.getPersonalLibrary() as? Resource.Success)?.value ?: return@let
|
_pages.postValue(Resource.Loading())
|
||||||
|
val libraryResource = repo.getPersonalLibrary()
|
||||||
|
if (libraryResource is Resource.Failure) {
|
||||||
|
_pages.postValue(libraryResource)
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
val library = (libraryResource as? Resource.Success)?.value ?: return@let
|
||||||
|
|
||||||
repo.requireLibraryRefresh = false
|
repo.requireLibraryRefresh = false
|
||||||
|
|
||||||
val listSubset = library.allLibraryItems.groupBy { it.listName }
|
val listSubset = library.allLibraryItems.groupBy { it.listName }
|
||||||
|
@ -97,7 +104,7 @@ class LibraryViewModel : ViewModel() {
|
||||||
it.value
|
it.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_pages.postValue(pages)
|
_pages.postValue(Resource.Success(pages))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,11 @@ import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.plugins.PLUGINS_KEY
|
import com.lagradost.cloudstream3.plugins.PLUGINS_KEY
|
||||||
import com.lagradost.cloudstream3.plugins.PLUGINS_KEY_LOCAL
|
import com.lagradost.cloudstream3.plugins.PLUGINS_KEY_LOCAL
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_CACHED_LIST
|
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_CACHED_LIST
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_SHOULD_UPDATE_LIST
|
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_TOKEN_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_TOKEN_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_UNIXTIME_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_UNIXTIME_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_USER_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_USER_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_REFRESH_TOKEN_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_REFRESH_TOKEN_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_SHOULD_UPDATE_LIST
|
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_TOKEN_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_TOKEN_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_UNIXTIME_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_UNIXTIME_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_USER_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_USER_KEY
|
||||||
|
@ -52,12 +50,10 @@ object BackupUtils {
|
||||||
// When sharing backup we do not want to transfer what is essentially the password
|
// When sharing backup we do not want to transfer what is essentially the password
|
||||||
ANILIST_TOKEN_KEY,
|
ANILIST_TOKEN_KEY,
|
||||||
ANILIST_CACHED_LIST,
|
ANILIST_CACHED_LIST,
|
||||||
ANILIST_SHOULD_UPDATE_LIST,
|
|
||||||
ANILIST_UNIXTIME_KEY,
|
ANILIST_UNIXTIME_KEY,
|
||||||
ANILIST_USER_KEY,
|
ANILIST_USER_KEY,
|
||||||
MAL_TOKEN_KEY,
|
MAL_TOKEN_KEY,
|
||||||
MAL_REFRESH_TOKEN_KEY,
|
MAL_REFRESH_TOKEN_KEY,
|
||||||
MAL_SHOULD_UPDATE_LIST,
|
|
||||||
MAL_CACHED_LIST,
|
MAL_CACHED_LIST,
|
||||||
MAL_UNIXTIME_KEY,
|
MAL_UNIXTIME_KEY,
|
||||||
MAL_USER_KEY,
|
MAL_USER_KEY,
|
||||||
|
|
|
@ -124,6 +124,19 @@
|
||||||
|
|
||||||
<!-- </com.google.android.material.appbar.AppBarLayout>-->
|
<!-- </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
|
<com.google.android.material.tabs.TabLayout
|
||||||
android:id="@+id/library_tab_layout"
|
android:id="@+id/library_tab_layout"
|
||||||
|
|
Loading…
Reference in a new issue