forked from recloudstream/cloudstream
range and download fix
This commit is contained in:
parent
de149172bc
commit
3e2836f462
6 changed files with 153 additions and 60 deletions
|
@ -419,7 +419,7 @@ object UIHelper {
|
||||||
|
|
||||||
/**id, string */
|
/**id, string */
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
fun View.popupMenuNoIconsAndNoStringres(
|
fun View.popupMenuNoIconsAndNoStringRes(
|
||||||
items: List<Pair<Int, String>>,
|
items: List<Pair<Int, String>>,
|
||||||
onMenuItemClick: MenuItem.() -> Unit,
|
onMenuItemClick: MenuItem.() -> Unit,
|
||||||
): PopupMenu {
|
): PopupMenu {
|
||||||
|
|
|
@ -211,7 +211,10 @@ class ShiroProvider : MainAPI() {
|
||||||
val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
|
val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
|
||||||
val data = mapped.data
|
val data = mapped.data
|
||||||
val isDubbed = data.language == "dubbed"
|
val isDubbed = data.language == "dubbed"
|
||||||
val episodes = ArrayList<AnimeEpisode>(data.episodes?.map { AnimeEpisode(it.videos[0].video_id) }
|
val episodes =
|
||||||
|
ArrayList<AnimeEpisode>(
|
||||||
|
data.episodes?.distinctBy { it.episode_number }?.sortedBy { it.episode_number }
|
||||||
|
?.map { AnimeEpisode(it.videos[0].video_id) }
|
||||||
?: ArrayList<AnimeEpisode>())
|
?: ArrayList<AnimeEpisode>())
|
||||||
val status = when (data.status) {
|
val status = when (data.status) {
|
||||||
"current" -> ShowStatus.Ongoing
|
"current" -> ShowStatus.Ongoing
|
||||||
|
|
|
@ -51,7 +51,7 @@ class EpisodeAdapter(
|
||||||
@LayoutRes
|
@LayoutRes
|
||||||
private var layout: Int = 0
|
private var layout: Int = 0
|
||||||
fun updateLayout() {
|
fun updateLayout() {
|
||||||
layout = if (cardList.filter { it.poster != null }.size >= cardList.size / 2)
|
layout = if (cardList.filter { it.poster != null }.size >= cardList.size / 2f) // If over half has posters then use the large layout
|
||||||
R.layout.result_episode_large
|
R.layout.result_episode_large
|
||||||
else R.layout.result_episode
|
else R.layout.result_episode
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,14 +43,13 @@ import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
||||||
import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
|
import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
import com.lagradost.cloudstream3.UIHelper.requestRW
|
import com.lagradost.cloudstream3.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.setUpButton
|
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.setUpMaterialButton
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.setUpMaterialButton
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerData
|
import com.lagradost.cloudstream3.ui.player.PlayerData
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||||
|
@ -206,6 +205,7 @@ class ResultFragment : Fragment() {
|
||||||
private var currentPoster: String? = null
|
private var currentPoster: String? = null
|
||||||
private var currentId: Int? = null
|
private var currentId: Int? = null
|
||||||
private var currentIsMovie: Boolean? = null
|
private var currentIsMovie: Boolean? = null
|
||||||
|
private var episodeRanges: List<String>? = null
|
||||||
|
|
||||||
var url: String? = null
|
var url: String? = null
|
||||||
|
|
||||||
|
@ -666,8 +666,6 @@ class ResultFragment : Fragment() {
|
||||||
allEpisodesSubs = it
|
allEpisodesSubs = it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
observe(viewModel.selectedSeason) { season ->
|
observe(viewModel.selectedSeason) { season ->
|
||||||
result_season_button?.text = fromIndexToSeasonText(season)
|
result_season_button?.text = fromIndexToSeasonText(season)
|
||||||
}
|
}
|
||||||
|
@ -675,7 +673,7 @@ class ResultFragment : Fragment() {
|
||||||
observe(viewModel.seasonSelections) { seasonList ->
|
observe(viewModel.seasonSelections) { seasonList ->
|
||||||
result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE
|
result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE
|
||||||
result_season_button?.setOnClickListener {
|
result_season_button?.setOnClickListener {
|
||||||
result_season_button?.popupMenuNoIconsAndNoStringres(
|
result_season_button?.popupMenuNoIconsAndNoStringRes(
|
||||||
items = seasonList
|
items = seasonList
|
||||||
.map { Pair(it ?: -2, fromIndexToSeasonText(it)) },
|
.map { Pair(it ?: -2, fromIndexToSeasonText(it)) },
|
||||||
) {
|
) {
|
||||||
|
@ -689,7 +687,6 @@ class ResultFragment : Fragment() {
|
||||||
|
|
||||||
observe(viewModel.publicEpisodes) { episodes ->
|
observe(viewModel.publicEpisodes) { episodes ->
|
||||||
if (result_episodes == null || result_episodes.adapter == null) return@observe
|
if (result_episodes == null || result_episodes.adapter == null) return@observe
|
||||||
result_episodes_text.text = "${episodes.size} Episode${if (episodes.size == 1) "" else "s"}"
|
|
||||||
currentEpisodes = episodes
|
currentEpisodes = episodes
|
||||||
activity?.runOnUiThread {
|
activity?.runOnUiThread {
|
||||||
(result_episodes.adapter as EpisodeAdapter).cardList = episodes
|
(result_episodes.adapter as EpisodeAdapter).cardList = episodes
|
||||||
|
@ -698,6 +695,28 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observe(viewModel.selectedRange) { range ->
|
||||||
|
result_episode_select?.text = range
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.rangeOptions) { range ->
|
||||||
|
episodeRanges = range
|
||||||
|
result_episode_select?.visibility = if (range.size <= 1) GONE else VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
result_episode_select.setOnClickListener {
|
||||||
|
val ranges = episodeRanges
|
||||||
|
if (ranges != null) {
|
||||||
|
it.popupMenuNoIconsAndNoStringRes(ranges.mapIndexed { index, s -> Pair(index, s) }.toList()) {
|
||||||
|
viewModel.changeRange(requireContext(), itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.publicEpisodesCount) { count ->
|
||||||
|
result_episodes_text.text = "$count Episode${if (count == 1) "" else "s"}"
|
||||||
|
}
|
||||||
|
|
||||||
observe(viewModel.id) {
|
observe(viewModel.id) {
|
||||||
currentId = it
|
currentId = it
|
||||||
}
|
}
|
||||||
|
@ -820,6 +839,7 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d.type == TvType.Movie && d is MovieLoadResponse) {
|
if (d.type == TvType.Movie && d is MovieLoadResponse) {
|
||||||
|
val hasDownloadSupport = api.hasDownloadSupport
|
||||||
result_movie_parent.visibility = VISIBLE
|
result_movie_parent.visibility = VISIBLE
|
||||||
result_episodes_text.visibility = GONE
|
result_episodes_text.visibility = GONE
|
||||||
result_episodes.visibility = GONE
|
result_episodes.visibility = GONE
|
||||||
|
@ -835,11 +855,14 @@ class ResultFragment : Fragment() {
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// result_options.setOnClickListener {
|
// result_options.setOnClickListener {
|
||||||
// val card = currentEpisodes?.first() ?: return@setOnClickListener
|
// val card = currentEpisodes?.first() ?: return@setOnClickListener
|
||||||
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
result_download_movie.visibility = if (hasDownloadSupport) VISIBLE else GONE
|
||||||
|
if (hasDownloadSupport) {
|
||||||
val localId = d.getId()
|
val localId = d.getId()
|
||||||
val file =
|
val file =
|
||||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), localId)
|
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), localId)
|
||||||
|
@ -885,6 +908,7 @@ class ResultFragment : Fragment() {
|
||||||
handleDownloadClick(activity, currentHeaderName, downloadClickEvent)
|
handleDownloadClick(activity, currentHeaderName, downloadClickEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result_movie_parent.visibility = GONE
|
result_movie_parent.visibility = GONE
|
||||||
result_episodes_text.visibility = VISIBLE
|
result_episodes_text.visibility = VISIBLE
|
||||||
|
|
|
@ -16,13 +16,23 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
const val EPISODE_RANGE_SIZE = 50
|
||||||
|
const val EPISODE_RANGE_OVERLOAD = 60
|
||||||
|
|
||||||
class ResultViewModel : ViewModel() {
|
class ResultViewModel : ViewModel() {
|
||||||
private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData()
|
private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData()
|
||||||
private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
||||||
private val _publicEpisodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
private val _publicEpisodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
||||||
|
private val _publicEpisodesCount: MutableLiveData<Int> = MutableLiveData() // before the sorting
|
||||||
|
private val _rangeOptions: MutableLiveData<List<String>> = MutableLiveData()
|
||||||
|
val selectedRange: MutableLiveData<String> = MutableLiveData()
|
||||||
|
private val selectedRangeInt: MutableLiveData<Int> = MutableLiveData()
|
||||||
|
val rangeOptions: LiveData<List<String>> = _rangeOptions
|
||||||
|
|
||||||
val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse
|
val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse
|
||||||
val episodes: LiveData<List<ResultEpisode>> get() = _episodes
|
val episodes: LiveData<List<ResultEpisode>> get() = _episodes
|
||||||
val publicEpisodes: LiveData<List<ResultEpisode>> get() = _publicEpisodes
|
val publicEpisodes: LiveData<List<ResultEpisode>> get() = _publicEpisodes
|
||||||
|
val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount
|
||||||
|
|
||||||
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
||||||
|
|
||||||
|
@ -46,7 +56,7 @@ class ResultViewModel : ViewModel() {
|
||||||
_watchStatus.postValue(currentWatch)
|
_watchStatus.postValue(currentWatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterEpisodes(context: Context, list: List<ResultEpisode>?, selection: Int?) {
|
private fun filterEpisodes(context: Context, list: List<ResultEpisode>?, selection: Int?, range: Int?) {
|
||||||
if (list == null) return
|
if (list == null) return
|
||||||
val seasonTypes = HashMap<Int?, Boolean>()
|
val seasonTypes = HashMap<Int?, Boolean>()
|
||||||
for (i in list) {
|
for (i in list) {
|
||||||
|
@ -62,11 +72,51 @@ class ResultViewModel : ViewModel() {
|
||||||
if (internalId != null) context.setResultSeason(internalId, realSelection)
|
if (internalId != null) context.setResultSeason(internalId, realSelection)
|
||||||
|
|
||||||
selectedSeason.postValue(realSelection ?: -2)
|
selectedSeason.postValue(realSelection ?: -2)
|
||||||
_publicEpisodes.postValue(list.filter { it.season == realSelection })
|
|
||||||
|
var currentList = list.filter { it.season == realSelection }
|
||||||
|
_publicEpisodesCount.postValue(currentList.size)
|
||||||
|
|
||||||
|
val rangeList = ArrayList<String>()
|
||||||
|
for (i in currentList.indices step EPISODE_RANGE_SIZE) {
|
||||||
|
if (i + EPISODE_RANGE_SIZE < currentList.size) {
|
||||||
|
rangeList.add("${i + 1}-${i + EPISODE_RANGE_SIZE}")
|
||||||
|
} else {
|
||||||
|
rangeList.add("${i + 1}-${currentList.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_rangeOptions.postValue(rangeList)
|
||||||
|
|
||||||
|
val cRange = range ?: if (selection != null) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
selectedRangeInt.value ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val realRange = if (cRange * EPISODE_RANGE_SIZE > currentList.size) {
|
||||||
|
currentList.size / EPISODE_RANGE_SIZE
|
||||||
|
} else {
|
||||||
|
cRange
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedRangeInt.postValue(realRange)
|
||||||
|
selectedRange.postValue(rangeList[realRange])
|
||||||
|
|
||||||
|
if (currentList.size > EPISODE_RANGE_OVERLOAD) {
|
||||||
|
currentList = currentList.subList(
|
||||||
|
realRange * EPISODE_RANGE_SIZE,
|
||||||
|
minOf(currentList.size, (realRange + 1) * EPISODE_RANGE_SIZE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_publicEpisodes.postValue(currentList)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeSeason(context: Context, selection: Int?) {
|
fun changeSeason(context: Context, selection: Int?) {
|
||||||
filterEpisodes(context, _episodes.value, selection)
|
filterEpisodes(context, _episodes.value, selection, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeRange(context: Context, range: Int?) {
|
||||||
|
filterEpisodes(context, _episodes.value, null, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateEpisodes(context: Context, localId: Int?, list: List<ResultEpisode>, selection: Int?) {
|
private fun updateEpisodes(context: Context, localId: Int?, list: List<ResultEpisode>, selection: Int?) {
|
||||||
|
@ -74,7 +124,7 @@ class ResultViewModel : ViewModel() {
|
||||||
filterEpisodes(
|
filterEpisodes(
|
||||||
context,
|
context,
|
||||||
list,
|
list,
|
||||||
if (selection == -1) context.getResultSeason(localId ?: id.value ?: return) else selection
|
if (selection == -1) context.getResultSeason(localId ?: id.value ?: return) else selection, null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp">
|
android:layout_height="50dp">
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:visibility="visible"
|
android:visibility="gone"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
app:cornerRadius="4dp"
|
app:cornerRadius="4dp"
|
||||||
android:id="@+id/result_bookmark_button"
|
android:id="@+id/result_bookmark_button"
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
app:iconTint="?attr/textColor"
|
app:iconTint="?attr/textColor"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
app:icon="@drawable/ic_outline_remove_red_eye_24"
|
app:icon="@drawable/ic_outline_remove_red_eye_24"
|
||||||
android:backgroundTint="@color/itemBackground"
|
android:backgroundTint="?attr/grayBackground"
|
||||||
style="@style/Widget.MaterialComponents.Button"
|
style="@style/Widget.MaterialComponents.Button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="50dp">
|
android:layout_height="50dp">
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
android:max="100"
|
android:max="100"
|
||||||
android:layout_gravity="end|center_vertical"
|
android:layout_gravity="end|center_vertical"
|
||||||
android:progress="0"
|
android:progress="0"
|
||||||
android:visibility="visible"
|
android:visibility="gone"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
<!--
|
<!--
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
@ -401,11 +401,27 @@
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
app:cornerRadius="4dp"
|
|
||||||
android:id="@+id/result_season_button"
|
android:id="@+id/result_season_button"
|
||||||
tools:text="Subbed"
|
tools:text="Season 1"
|
||||||
|
|
||||||
app:rippleColor="?attr/bitDarkerGrayBackground"
|
app:rippleColor="?attr/grayBackground"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
app:iconTint="?attr/textColor"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
|
||||||
|
android:backgroundTint="@color/itemBackground"
|
||||||
|
style="@style/Widget.MaterialComponents.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_height="50dp">
|
||||||
|
</com.google.android.material.button.MaterialButton>
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:visibility="visible"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:id="@+id/result_episode_select"
|
||||||
|
tools:text="50-100"
|
||||||
|
|
||||||
|
app:rippleColor="?attr/grayBackground"
|
||||||
android:textColor="?attr/textColor"
|
android:textColor="?attr/textColor"
|
||||||
app:iconTint="?attr/textColor"
|
app:iconTint="?attr/textColor"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
|
|
Loading…
Reference in a new issue