fixed homepage

This commit is contained in:
reduplicated 2022-11-01 00:29:10 +01:00
parent 1c494f0ce2
commit f268418190
7 changed files with 316 additions and 227 deletions

View file

@ -1,40 +1,39 @@
package com.lagradost.cloudstream3.plugins package com.lagradost.cloudstream3.plugins
import android.app.* import android.app.*
import dalvik.system.PathClassLoader import android.content.Context
import com.google.gson.Gson
import android.content.res.AssetManager import android.content.res.AssetManager
import android.content.res.Resources import android.content.res.Resources
import android.os.Environment
import android.widget.Toast
import android.content.Context
import android.os.Build import android.os.Build
import android.os.Environment
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.google.gson.Gson
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.removePluginMapping
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.plugins.RepositoryManager.ONLINE_PLUGINS_FOLDER
import com.lagradost.cloudstream3.plugins.RepositoryManager.downloadPluginToFile
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.plugins.RepositoryManager.getRepoPlugins
import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
import com.lagradost.cloudstream3.APIHolder.removePluginMapping
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.mvvm.debugPrint import com.lagradost.cloudstream3.mvvm.debugPrint
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.plugins.RepositoryManager.ONLINE_PLUGINS_FOLDER
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.plugins.RepositoryManager.downloadPluginToFile
import com.lagradost.cloudstream3.plugins.RepositoryManager.getRepoPlugins
import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
import com.lagradost.cloudstream3.utils.extractorApis import com.lagradost.cloudstream3.utils.extractorApis
import dalvik.system.PathClassLoader
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import java.io.File import java.io.File
@ -217,7 +216,7 @@ object PluginManager {
* 3. If outdated download and load the plugin * 3. If outdated download and load the plugin
* 4. Else load the plugin normally * 4. Else load the plugin normally
**/ **/
fun updateAllOnlinePluginsAndLoadThem(activity: Activity) = ioSafe { fun updateAllOnlinePluginsAndLoadThem(activity: Activity) {
// Load all plugins as fast as possible! // Load all plugins as fast as possible!
loadAllOnlinePlugins(activity) loadAllOnlinePlugins(activity)
@ -227,7 +226,7 @@ object PluginManager {
val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY) val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)
?: emptyArray()) + PREBUILT_REPOSITORIES ?: emptyArray()) + PREBUILT_REPOSITORIES
val onlinePlugins = urls.toList().amap { val onlinePlugins = urls.toList().apmap {
getRepoPlugins(it.url)?.toList() ?: emptyList() getRepoPlugins(it.url)?.toList() ?: emptyList()
}.flatten().distinctBy { it.second.url } }.flatten().distinctBy { it.second.url }
@ -248,7 +247,7 @@ object PluginManager {
val updatedPlugins = mutableListOf<String>() val updatedPlugins = mutableListOf<String>()
outdatedPlugins.amap { pluginData -> outdatedPlugins.apmap { pluginData ->
if (pluginData.isDisabled) { if (pluginData.isDisabled) {
//updatedPlugins.add(activity.getString(R.string.single_plugin_disabled, pluginData.onlineData.second.name)) //updatedPlugins.add(activity.getString(R.string.single_plugin_disabled, pluginData.onlineData.second.name))
unloadPlugin(pluginData.savedData.filePath) unloadPlugin(pluginData.savedData.filePath)
@ -279,9 +278,9 @@ object PluginManager {
/** /**
* Use updateAllOnlinePluginsAndLoadThem * Use updateAllOnlinePluginsAndLoadThem
* */ * */
fun loadAllOnlinePlugins(activity: Activity) = ioSafe { fun loadAllOnlinePlugins(activity: Activity) {
// Load all plugins as fast as possible! // Load all plugins as fast as possible!
(getPluginsOnline()).toList().amap { pluginData -> (getPluginsOnline()).toList().apmap { pluginData ->
loadPlugin( loadPlugin(
activity, activity,
File(pluginData.filePath), File(pluginData.filePath),
@ -290,7 +289,7 @@ object PluginManager {
} }
} }
fun loadAllLocalPlugins(activity: Activity) = ioSafe { fun loadAllLocalPlugins(activity: Activity) {
val dir = File(LOCAL_PLUGINS_PATH) val dir = File(LOCAL_PLUGINS_PATH)
removeKey(PLUGINS_KEY_LOCAL) removeKey(PLUGINS_KEY_LOCAL)
@ -298,7 +297,7 @@ object PluginManager {
val res = dir.mkdirs() val res = dir.mkdirs()
if (!res) { if (!res) {
Log.w(TAG, "Failed to create local directories") Log.w(TAG, "Failed to create local directories")
return@ioSafe return
} }
} }

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.ui.home package com.lagradost.cloudstream3.ui.home
import android.animation.LayoutTransition
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
@ -26,13 +25,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.transition.ChangeBounds import androidx.transition.ChangeBounds
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.allProviders
import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
@ -554,7 +553,9 @@ class HomeFragment : Fragment() {
is Resource.Success -> { is Resource.Success -> {
home_preview?.isVisible = true home_preview?.isVisible = true
(home_preview_viewpager?.adapter as? HomeScrollAdapter)?.apply { (home_preview_viewpager?.adapter as? HomeScrollAdapter)?.apply {
setItems(preview.value) if (!setItems(preview.value.second, preview.value.first)) {
home_preview_viewpager?.setCurrentItem(0, false)
}
// home_preview_viewpager?.setCurrentItem(1000, false) // home_preview_viewpager?.setCurrentItem(1000, false)
} }
@ -563,6 +564,10 @@ class HomeFragment : Fragment() {
//} //}
} }
else -> { else -> {
(home_preview_viewpager?.adapter as? HomeScrollAdapter)?.setItems(
listOf(),
false
)
home_preview?.isVisible = false home_preview?.isVisible = false
context?.fixPaddingStatusbar(home_watch_holder) context?.fixPaddingStatusbar(home_watch_holder)
} }
@ -577,59 +582,75 @@ class HomeFragment : Fragment() {
} }
home_preview_viewpager?.apply { home_preview_viewpager?.apply {
setPageTransformer(false, HomeScrollTransformer()) setPageTransformer(HomeScrollTransformer())
adapter = HomeScrollAdapter { load -> val callback: OnPageChangeCallback = object : OnPageChangeCallback() {
load.apply { override fun onPageSelected(position: Int) {
home_preview_title_holder?.let { parent -> (home_preview_viewpager?.adapter as? HomeScrollAdapter)?.apply {
TransitionManager.beginDelayedTransition(parent, ChangeBounds()) if (position >= itemCount - 1 && hasMoreItems) {
} hasMoreItems = false // dont make two requests
homeViewModel.loadMoreHomeScrollResponses()
home_preview_tags?.text = tags?.joinToString("") ?: ""
home_preview_tags?.isGone = tags.isNullOrEmpty()
home_preview_image?.setImage(posterUrl, posterHeaders)
home_preview_title?.text = name
home_preview_play?.setOnClickListener {
activity?.loadResult(url, apiName, START_ACTION_RESUME_LATEST)
//activity.loadSearchResult(url, START_ACTION_RESUME_LATEST)
}
home_preview_info?.setOnClickListener {
activity?.loadResult(url, apiName)
//activity.loadSearchResult(random)
}
// very ugly code, but I dont care
val watchType = DataStoreHelper.getResultWatchState(load.getId())
home_preview_bookmark?.setText(watchType.stringRes)
home_preview_bookmark?.setCompoundDrawablesWithIntrinsicBounds(
null,
getDrawable(home_preview_bookmark.context, watchType.iconRes),
null,
null
)
home_preview_bookmark?.setOnClickListener { fab ->
activity?.showBottomDialog(
WatchType.values().map { fab.context.getString(it.stringRes) }
.toList(),
DataStoreHelper.getResultWatchState(load.getId()).ordinal,
fab.context.getString(R.string.action_add_to_bookmarks),
showApply = false,
{}) {
val newValue = WatchType.values()[it]
home_preview_bookmark?.setCompoundDrawablesWithIntrinsicBounds(
null,
getDrawable(home_preview_bookmark.context, newValue.iconRes),
null,
null
)
home_preview_bookmark?.setText(newValue.stringRes)
updateWatchStatus(load, newValue)
reloadStored()
} }
getItem(position)
?.apply {
home_preview_title_holder?.let { parent ->
TransitionManager.beginDelayedTransition(parent, ChangeBounds())
}
// home_preview_tags?.text = tags?.joinToString(" • ") ?: ""
// home_preview_tags?.isGone = tags.isNullOrEmpty()
// home_preview_image?.setImage(posterUrl, posterHeaders)
// home_preview_title?.text = name
home_preview_play?.setOnClickListener {
activity?.loadResult(url, apiName, START_ACTION_RESUME_LATEST)
//activity.loadSearchResult(url, START_ACTION_RESUME_LATEST)
}
home_preview_info?.setOnClickListener {
activity?.loadResult(url, apiName)
//activity.loadSearchResult(random)
}
// very ugly code, but I dont care
val watchType = DataStoreHelper.getResultWatchState(this.getId())
home_preview_bookmark?.setText(watchType.stringRes)
home_preview_bookmark?.setCompoundDrawablesWithIntrinsicBounds(
null,
getDrawable(home_preview_bookmark.context, watchType.iconRes),
null,
null
)
home_preview_bookmark?.setOnClickListener { fab ->
activity?.showBottomDialog(
WatchType.values()
.map { fab.context.getString(it.stringRes) }
.toList(),
DataStoreHelper.getResultWatchState(this.getId()).ordinal,
fab.context.getString(R.string.action_add_to_bookmarks),
showApply = false,
{}) {
val newValue = WatchType.values()[it]
home_preview_bookmark?.setCompoundDrawablesWithIntrinsicBounds(
null,
getDrawable(
home_preview_bookmark.context,
newValue.iconRes
),
null,
null
)
home_preview_bookmark?.setText(newValue.stringRes)
updateWatchStatus(this, newValue)
reloadStored()
}
}
}
} }
} }
} }
registerOnPageChangeCallback(callback)
adapter = HomeScrollAdapter()
} }
observe(homeViewModel.apiName) { apiName -> observe(homeViewModel.apiName) { apiName ->

View file

@ -1,60 +1,89 @@
package com.lagradost.cloudstream3.ui.home package com.lagradost.cloudstream3.ui.home
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import androidx.core.view.isGone
import androidx.viewpager.widget.PagerAdapter import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
import kotlinx.android.synthetic.main.home_scroll_view.view.*
class HomeScrollAdapter(private val onPrimaryCallback: (LoadResponse) -> Unit) : PagerAdapter() { class HomeScrollAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var items: List<LoadResponse> = listOf() private var items: MutableList<LoadResponse> = mutableListOf()
var hasMoreItems: Boolean = false
fun setItems(newItems: List<LoadResponse>) { fun getItem(position: Int) : LoadResponse? {
items = newItems return items.getOrNull(position)
notifyDataSetChanged()
} }
override fun getCount(): Int { fun setItems(newItems: List<LoadResponse>, hasNext: Boolean): Boolean {
return Int.MAX_VALUE//items.size val isSame = newItems.firstOrNull()?.url == items.firstOrNull()?.url
hasMoreItems = hasNext
val diffResult = DiffUtil.calculateDiff(
HomeScrollDiffCallback(this.items, newItems)
)
items.clear()
items.addAll(newItems)
diffResult.dispatchUpdatesTo(this)
return isSame
} }
override fun getItemPosition(`object`: Any): Int { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return POSITION_NONE//super.getItemPosition(`object`) return CardViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.home_scroll_view, parent, false),
)
} }
private fun getItemAtPosition(idx: Int): LoadResponse { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
return items[idx % items.size] when (holder) {
is CardViewHolder -> {
holder.bind(items[position])
}
}
} }
override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) { class CardViewHolder
super.setPrimaryItem(container, position, `object`) constructor(
onPrimaryCallback.invoke(getItemAtPosition(position)) itemView: View,
) :
RecyclerView.ViewHolder(itemView) {
fun bind(card: LoadResponse) {
card.apply {
itemView.home_scroll_preview_tags?.text = tags?.joinToString("") ?: ""
itemView.home_scroll_preview_tags?.isGone = tags.isNullOrEmpty()
itemView.home_scroll_preview?.setImage(posterUrl, posterHeaders)
itemView.home_scroll_preview_title?.text = name
}
}
} }
override fun instantiateItem(container: ViewGroup, position: Int): Any { class HomeScrollDiffCallback(
val image = ImageView(container.context) private val oldList: List<LoadResponse>,
val item = getItemAtPosition(position) private val newList: List<LoadResponse>
image.scaleType = ImageView.ScaleType.CENTER_CROP ) :
image.setImage(item.posterUrl ?: item.backgroundPosterUrl, item.posterHeaders) DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].url == newList[newItemPosition].url
// val itemView: View = mLayoutInflater.inflate(R.layout.pager_item, container, false) override fun getOldListSize() = oldList.size
// val imageView: ImageView = itemView.findViewById<View>(R.id.imageView) as ImageView override fun getNewListSize() = newList.size
// imageView.setImageResource(mResources.get(position))
container.addView(image) override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition] == newList[newItemPosition]
return image
} }
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { override fun getItemCount(): Int {
container.removeView(`object` as View) return items.size
}
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view === `object`
} }
} }

View file

@ -1,13 +1,23 @@
package com.lagradost.cloudstream3.ui.home package com.lagradost.cloudstream3.ui.home
import android.view.View import android.view.View
import androidx.viewpager.widget.ViewPager import androidx.viewpager2.widget.ViewPager2
class HomeScrollTransformer : ViewPager.PageTransformer { class HomeScrollTransformer : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) { override fun transformPage(page: View, position: Float) {
//page.translationX = -position * page.width / 2.0f
//val params = RecyclerView.LayoutParams(
// RecyclerView.LayoutParams.MATCH_PARENT,
// 0
//)
//page.layoutParams = params
//progressBar?.layoutParams = params
val padding = (-position * page.width / 2).toInt()
page.setPadding( page.setPadding(
maxOf(0, (-position * page.width / 2).toInt()), 0, padding, 0,
maxOf(0, (position * page.width / 2).toInt()), 0 -padding, 0
) )
} }
} }

View file

@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.filterHomePageListByFilmQuality import com.lagradost.cloudstream3.APIHolder.filterHomePageListByFilmQuality
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
@ -12,17 +13,12 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.context import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds
@ -35,7 +31,6 @@ import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
import kotlin.collections.set import kotlin.collections.set
@ -49,6 +44,8 @@ class HomeViewModel : ViewModel() {
private val _randomItems = MutableLiveData<List<SearchResponse>?>(null) private val _randomItems = MutableLiveData<List<SearchResponse>?>(null)
val randomItems: LiveData<List<SearchResponse>?> = _randomItems val randomItems: LiveData<List<SearchResponse>?> = _randomItems
private var currentShuffledList: List<SearchResponse> = listOf()
private fun autoloadRepo(): APIRepository { private fun autoloadRepo(): APIRepository {
return APIRepository(apis.first { it.hasMainPage }) return APIRepository(apis.first { it.hasMainPage })
} }
@ -61,9 +58,12 @@ class HomeViewModel : ViewModel() {
val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks
private val _resumeWatching = MutableLiveData<List<SearchResponse>>() private val _resumeWatching = MutableLiveData<List<SearchResponse>>()
private val _preview = MutableLiveData<Resource<List<LoadResponse>>>() private val _preview = MutableLiveData<Resource<Pair<Boolean, List<LoadResponse>>>>()
private val previewResponses = mutableListOf<LoadResponse>()
private val previewResponsesAdded = mutableSetOf<String>()
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
val preview: LiveData<Resource<List<LoadResponse>>> = _preview val preview: LiveData<Resource<Pair<Boolean, List<LoadResponse>>>> = _preview
fun loadResumeWatching() = viewModelScope.launchSafe { fun loadResumeWatching() = viewModelScope.launchSafe {
val resumeWatching = withContext(Dispatchers.IO) { val resumeWatching = withContext(Dispatchers.IO) {
@ -212,6 +212,40 @@ class HomeViewModel : ViewModel() {
expandAndReturn(name) expandAndReturn(name)
} }
// returns the amount of items added and modifies current
private suspend fun updatePreviewResponses(
current: MutableList<LoadResponse>,
alreadyAdded: MutableSet<String>,
shuffledList: List<SearchResponse>,
size: Int
): Int {
var count = 0
val addItems = arrayListOf<SearchResponse>()
for (searchResponse in shuffledList) {
if (!alreadyAdded.contains(searchResponse.url)) {
addItems.add(searchResponse)
previewResponsesAdded.add(searchResponse.url)
if (++count >= size) {
break
}
}
}
val add = addItems.amap { searchResponse ->
repo?.load(searchResponse.url)
}.mapNotNull { if (it != null && it is Resource.Success) it.value else null }
current.addAll(add)
return add.size
}
private var addJob: Job? = null
fun loadMoreHomeScrollResponses() {
addJob = ioSafe {
updatePreviewResponses(previewResponses, previewResponsesAdded, currentShuffledList, 1)
_preview.postValue(Resource.Success((previewResponsesAdded.size < currentShuffledList.size) to previewResponses))
}
}
private fun load(api: MainAPI?) = ioSafe { private fun load(api: MainAPI?) = ioSafe {
repo = if (api != null) { repo = if (api != null) {
@ -226,6 +260,7 @@ class HomeViewModel : ViewModel() {
if (repo?.hasMainPage == true) { if (repo?.hasMainPage == true) {
_page.postValue(Resource.Loading()) _page.postValue(Resource.Loading())
_preview.postValue(Resource.Loading()) _preview.postValue(Resource.Loading())
addJob?.cancel()
when (val data = repo?.getMainPage(1, null)) { when (val data = repo?.getMainPage(1, null)) {
is Resource.Success -> { is Resource.Success -> {
@ -241,64 +276,10 @@ class HomeViewModel : ViewModel() {
} }
val items = data.value.mapNotNull { it?.items }.flatten() val items = data.value.mapNotNull { it?.items }.flatten()
val responses = ioWork {
items.flatMap { it.list }.shuffled().take(6).map { searchResponse ->
async { repo?.load(searchResponse.url) }
}.map { it.await() }.mapNotNull { if (it != null && it is Resource.Success) it.value else null } }
//.amap { searchResponse ->
// repo?.load(searchResponse.url)
///}
//.map { searchResponse ->
// async { repo?.load(searchResponse.url) }
// }.map { it.await() }
if (responses.isEmpty()) { previewResponses.clear()
_preview.postValue( previewResponsesAdded.clear()
Resource.Failure(
false,
null,
null,
"No homepage responses"
)
)
} else {
_preview.postValue(Resource.Success(responses))
}
/*
items.randomOrNull()?.list?.randomOrNull()?.url?.let { url ->
// backup request in case first fails
var first = repo?.load(url)
if(first == null ||first is Resource.Failure) {
first = repo?.load(items.random().list.random().url)
}
first?.let {
_preview.postValue(it)
} ?: run {
_preview.postValue(
Resource.Failure(
false,
null,
null,
"No repo found, this should never happen"
)
)
}
} ?: run {
_preview.postValue(
Resource.Failure(
false,
null,
null,
"No homepage items"
)
)
}*/
_page.postValue(Resource.Success(expandable))
//val home = data.value //val home = data.value
if (items.isNotEmpty()) { if (items.isNotEmpty()) {
@ -313,9 +294,30 @@ class HomeViewModel : ViewModel() {
context?.filterSearchResultByFilmQuality(currentList.shuffled()) context?.filterSearchResultByFilmQuality(currentList.shuffled())
?: currentList.shuffled() ?: currentList.shuffled()
updatePreviewResponses(
previewResponses,
previewResponsesAdded,
randomItems,
3
)
_randomItems.postValue(randomItems) _randomItems.postValue(randomItems)
currentShuffledList = randomItems
} }
} }
if (previewResponses.isEmpty()) {
_preview.postValue(
Resource.Failure(
false,
null,
null,
"No homepage responses"
)
)
} else {
_preview.postValue(Resource.Success((previewResponsesAdded.size < currentShuffledList.size) to previewResponses))
}
_page.postValue(Resource.Success(expandable))
} catch (e: Exception) { } catch (e: Exception) {
_randomItems.postValue(emptyList()) _randomItems.postValue(emptyList())
logError(e) logError(e)

View file

@ -287,39 +287,23 @@
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
<androidx.viewpager.widget.ViewPager <androidx.viewpager2.widget.ViewPager2
android:id="@+id/home_preview_viewpager" android:id="@+id/home_preview_viewpager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:orientation="horizontal">
</androidx.viewpager.widget.ViewPager> </androidx.viewpager2.widget.ViewPager2>
<ImageView <ImageView
android:visibility="gone"
android:id="@+id/home_preview_image" android:id="@+id/home_preview_image"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:alpha="0.8" android:alpha="0.8"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:visibility="gone"
tools:src="@drawable/example_poster" /> tools:src="@drawable/example_poster" />
<View
android:id="@+id/title_shadow_top"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_gravity="top"
android:alpha="1"
android:background="@drawable/background_shadow"
android:rotation="180"
android:visibility="visible" />
<View
android:id="@+id/title_shadow"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="bottom"
android:background="@drawable/background_shadow" />
<LinearLayout <LinearLayout
android:id="@+id/home_padding" android:id="@+id/home_padding"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -363,44 +347,14 @@
--> -->
<LinearLayout <LinearLayout
android:id="@+id/home_preview_title_holder" android:id="@+id/home_preview_title_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="100dp"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:gravity="center" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/home_preview_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingBottom="10dp"
android:paddingHorizontal="30dp"
android:textColor="?attr/white"
android:textSize="17sp"
android:textStyle="bold"
tools:text="The Perfect Run" />
<!--<TextView
android:paddingStart="30dp"
android:paddingEnd="30dp"
android:id="@+id/home_season_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="5 seasons 50 episodes" />-->
<TextView
android:id="@+id/home_preview_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingStart="30dp"
android:paddingEnd="30dp"
android:textColor="?attr/white"
android:textSize="14sp"
tools:text="Hello • World • Tags" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="?attr/primaryGrayBackground"
android:layout_height="match_parent">
<ImageView
android:id="@+id/home_scroll_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
<View
android:id="@+id/title_shadow_top"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_gravity="top"
android:alpha="1"
android:background="@drawable/background_shadow"
android:rotation="180"
android:visibility="visible" />
<View
android:id="@+id/title_shadow"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="bottom"
android:background="@drawable/background_shadow" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="100dp"
android:orientation="vertical">
<TextView
android:id="@+id/home_scroll_preview_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:paddingHorizontal="30dp"
android:paddingBottom="10dp"
android:textColor="?attr/white"
android:textSize="17sp"
android:textStyle="bold"
tools:text="The Perfect Run" />
<!--<TextView
android:paddingStart="30dp"
android:paddingEnd="30dp"
android:id="@+id/home_season_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="5 seasons 50 episodes" />-->
<TextView
android:id="@+id/home_scroll_preview_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:paddingStart="30dp"
android:paddingEnd="30dp"
android:textColor="?attr/white"
android:textSize="14sp"
tools:text="Hello • World • Tags" />
</LinearLayout>
</FrameLayout>