mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
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 */
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun View.popupMenuNoIconsAndNoStringres(
|
||||
fun View.popupMenuNoIconsAndNoStringRes(
|
||||
items: List<Pair<Int, String>>,
|
||||
onMenuItemClick: MenuItem.() -> Unit,
|
||||
): PopupMenu {
|
||||
|
|
|
@ -211,8 +211,11 @@ class ShiroProvider : MainAPI() {
|
|||
val mapped = response.let { mapper.readValue<AnimePage>(it.text) }
|
||||
val data = mapped.data
|
||||
val isDubbed = data.language == "dubbed"
|
||||
val episodes = ArrayList<AnimeEpisode>(data.episodes?.map { AnimeEpisode(it.videos[0].video_id) }
|
||||
?: ArrayList<AnimeEpisode>())
|
||||
val episodes =
|
||||
ArrayList<AnimeEpisode>(
|
||||
data.episodes?.distinctBy { it.episode_number }?.sortedBy { it.episode_number }
|
||||
?.map { AnimeEpisode(it.videos[0].video_id) }
|
||||
?: ArrayList<AnimeEpisode>())
|
||||
val status = when (data.status) {
|
||||
"current" -> ShowStatus.Ongoing
|
||||
"finished" -> ShowStatus.Completed
|
||||
|
|
|
@ -51,7 +51,7 @@ class EpisodeAdapter(
|
|||
@LayoutRes
|
||||
private var layout: Int = 0
|
||||
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
|
||||
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.popCurrentPage
|
||||
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.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
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.player.PlayerData
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||
|
@ -206,6 +205,7 @@ class ResultFragment : Fragment() {
|
|||
private var currentPoster: String? = null
|
||||
private var currentId: Int? = null
|
||||
private var currentIsMovie: Boolean? = null
|
||||
private var episodeRanges: List<String>? = null
|
||||
|
||||
var url: String? = null
|
||||
|
||||
|
@ -666,8 +666,6 @@ class ResultFragment : Fragment() {
|
|||
allEpisodesSubs = it
|
||||
}
|
||||
|
||||
|
||||
|
||||
observe(viewModel.selectedSeason) { season ->
|
||||
result_season_button?.text = fromIndexToSeasonText(season)
|
||||
}
|
||||
|
@ -675,7 +673,7 @@ class ResultFragment : Fragment() {
|
|||
observe(viewModel.seasonSelections) { seasonList ->
|
||||
result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE
|
||||
result_season_button?.setOnClickListener {
|
||||
result_season_button?.popupMenuNoIconsAndNoStringres(
|
||||
result_season_button?.popupMenuNoIconsAndNoStringRes(
|
||||
items = seasonList
|
||||
.map { Pair(it ?: -2, fromIndexToSeasonText(it)) },
|
||||
) {
|
||||
|
@ -689,7 +687,6 @@ class ResultFragment : Fragment() {
|
|||
|
||||
observe(viewModel.publicEpisodes) { episodes ->
|
||||
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
|
||||
activity?.runOnUiThread {
|
||||
(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) {
|
||||
currentId = it
|
||||
}
|
||||
|
@ -820,6 +839,7 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
if (d.type == TvType.Movie && d is MovieLoadResponse) {
|
||||
val hasDownloadSupport = api.hasDownloadSupport
|
||||
result_movie_parent.visibility = VISIBLE
|
||||
result_episodes_text.visibility = GONE
|
||||
result_episodes.visibility = GONE
|
||||
|
@ -835,54 +855,58 @@ class ResultFragment : Fragment() {
|
|||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
|
||||
// result_options.setOnClickListener {
|
||||
// val card = currentEpisodes?.first() ?: return@setOnClickListener
|
||||
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
||||
// }
|
||||
|
||||
val localId = d.getId()
|
||||
val file =
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), localId)
|
||||
result_download_movie.visibility = if (hasDownloadSupport) VISIBLE else GONE
|
||||
if (hasDownloadSupport) {
|
||||
val localId = d.getId()
|
||||
val file =
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(requireContext(), localId)
|
||||
|
||||
setUpMaterialButton(
|
||||
file?.fileLength,
|
||||
file?.totalBytes,
|
||||
result_movie_progress_downloaded,
|
||||
result_download_movie,
|
||||
result_movie_text_progress,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
d.name,
|
||||
d.posterUrl,
|
||||
0,
|
||||
null,
|
||||
localId,
|
||||
localId,
|
||||
d.rating,
|
||||
d.plot
|
||||
)
|
||||
) { downloadClickEvent ->
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
|
||||
handleAction(
|
||||
EpisodeClickEvent(
|
||||
ACTION_DOWNLOAD_EPISODE,
|
||||
ResultEpisode(
|
||||
d.name,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
d.dataUrl,
|
||||
d.apiName,
|
||||
localId,
|
||||
0,
|
||||
0L,
|
||||
0L,
|
||||
null,
|
||||
null
|
||||
setUpMaterialButton(
|
||||
file?.fileLength,
|
||||
file?.totalBytes,
|
||||
result_movie_progress_downloaded,
|
||||
result_download_movie,
|
||||
result_movie_text_progress,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
d.name,
|
||||
d.posterUrl,
|
||||
0,
|
||||
null,
|
||||
localId,
|
||||
localId,
|
||||
d.rating,
|
||||
d.plot
|
||||
)
|
||||
) { downloadClickEvent ->
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
|
||||
handleAction(
|
||||
EpisodeClickEvent(
|
||||
ACTION_DOWNLOAD_EPISODE,
|
||||
ResultEpisode(
|
||||
d.name,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
d.dataUrl,
|
||||
d.apiName,
|
||||
localId,
|
||||
0,
|
||||
0L,
|
||||
0L,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
handleDownloadClick(activity, currentHeaderName, downloadClickEvent)
|
||||
} else {
|
||||
handleDownloadClick(activity, currentHeaderName, downloadClickEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -16,13 +16,23 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
const val EPISODE_RANGE_SIZE = 50
|
||||
const val EPISODE_RANGE_OVERLOAD = 60
|
||||
|
||||
class ResultViewModel : ViewModel() {
|
||||
private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData()
|
||||
private val _episodes: 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 episodes: LiveData<List<ResultEpisode>> get() = _episodes
|
||||
val publicEpisodes: LiveData<List<ResultEpisode>> get() = _publicEpisodes
|
||||
val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount
|
||||
|
||||
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
||||
|
||||
|
@ -46,7 +56,7 @@ class ResultViewModel : ViewModel() {
|
|||
_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
|
||||
val seasonTypes = HashMap<Int?, Boolean>()
|
||||
for (i in list) {
|
||||
|
@ -62,11 +72,51 @@ class ResultViewModel : ViewModel() {
|
|||
if (internalId != null) context.setResultSeason(internalId, realSelection)
|
||||
|
||||
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?) {
|
||||
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?) {
|
||||
|
@ -74,7 +124,7 @@ class ResultViewModel : ViewModel() {
|
|||
filterEpisodes(
|
||||
context,
|
||||
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_height="50dp">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:cornerRadius="4dp"
|
||||
android:id="@+id/result_bookmark_button"
|
||||
|
@ -202,7 +202,7 @@
|
|||
app:iconTint="?attr/textColor"
|
||||
android:textAllCaps="false"
|
||||
app:icon="@drawable/ic_outline_remove_red_eye_24"
|
||||
android:backgroundTint="@color/itemBackground"
|
||||
android:backgroundTint="?attr/grayBackground"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp">
|
||||
|
@ -345,7 +345,7 @@
|
|||
android:max="100"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:progress="0"
|
||||
android:visibility="visible"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
<!--
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
@ -401,11 +401,27 @@
|
|||
<com.google.android.material.button.MaterialButton
|
||||
android:visibility="visible"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:cornerRadius="4dp"
|
||||
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"
|
||||
app:iconTint="?attr/textColor"
|
||||
android:textAllCaps="false"
|
||||
|
|
Loading…
Reference in a new issue