mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
not done 2
This commit is contained in:
parent
3f19429805
commit
f57b12d89c
5 changed files with 312 additions and 267 deletions
|
@ -21,7 +21,6 @@ import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
|
@ -39,7 +38,6 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||||
|
@ -84,7 +82,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getFileName
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getFileName
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
@ -95,10 +92,8 @@ import kotlinx.android.synthetic.main.result_sync.*
|
||||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
const val START_ACTION_NORMAL = 0
|
const val START_ACTION_NORMAL = 0
|
||||||
const val START_ACTION_RESUME_LATEST = 1
|
const val START_ACTION_RESUME_LATEST = 1
|
||||||
|
@ -458,11 +453,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
|
0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
|
||||||
private lateinit var viewModel: ResultViewModel2 //by activityViewModels()
|
private lateinit var viewModel: ResultViewModel2 //by activityViewModels()
|
||||||
private lateinit var syncModel: SyncViewModel
|
private lateinit var syncModel: SyncViewModel
|
||||||
private var currentHeaderName: String? = null
|
|
||||||
private var currentType: TvType? = null
|
|
||||||
private var currentEpisodes: List<ResultEpisode>? = null
|
|
||||||
private var downloadButton: EasyDownloadButton? = null
|
|
||||||
private var syncdata: Map<String, String>? = null
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -490,13 +480,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
|
|
||||||
|
|
||||||
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
activity?.let {
|
activity?.let {
|
||||||
|
@ -563,52 +546,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
var startAction: Int? = null
|
var startAction: Int? = null
|
||||||
private var startValue: Int? = null
|
private var startValue: Int? = null
|
||||||
|
|
||||||
private fun setFormatText(textView: TextView?, @StringRes format: Int, arg: Any?) {
|
|
||||||
// java.util.IllegalFormatConversionException: f != java.lang.Integer
|
|
||||||
// This can fail with malformed formatting
|
|
||||||
normalSafeApiCall {
|
|
||||||
if (arg == null) {
|
|
||||||
textView?.isVisible = false
|
|
||||||
} else {
|
|
||||||
val text = context?.getString(format)?.format(arg)
|
|
||||||
if (text == null) {
|
|
||||||
textView?.isVisible = false
|
|
||||||
} else {
|
|
||||||
textView?.isVisible = true
|
|
||||||
textView?.text = text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setDuration(duration: Int?) {
|
|
||||||
setFormatText(result_meta_duration, R.string.duration_format, duration)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setShow(showStatus: ShowStatus?) {
|
|
||||||
val status = when (showStatus) {
|
|
||||||
null -> null
|
|
||||||
ShowStatus.Ongoing -> R.string.status_ongoing
|
|
||||||
ShowStatus.Completed -> R.string.status_completed
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == null) {
|
|
||||||
result_meta_status?.isVisible = false
|
|
||||||
} else {
|
|
||||||
context?.getString(status)?.let {
|
|
||||||
result_meta_status?.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setYear(year: Int?) {
|
|
||||||
setFormatText(result_meta_year, R.string.year_format, year)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setRating(rating: Int?) {
|
|
||||||
setFormatText(result_meta_rating, R.string.rating_format, rating?.div(1000f))
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentTrailers: List<ExtractorLink> = emptyList()
|
var currentTrailers: List<ExtractorLink> = emptyList()
|
||||||
var currentTrailerIndex = 0
|
var currentTrailerIndex = 0
|
||||||
|
|
||||||
|
@ -1339,54 +1276,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_episode_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
result_episode_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||||
result_dub_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
result_dub_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||||
|
|
||||||
observe(viewModel.selectedSeason) { season ->
|
|
||||||
result_season_button?.text = fromIndexToSeasonText(season)
|
|
||||||
}
|
|
||||||
|
|
||||||
observe(viewModel.seasonSelections) { seasonList ->
|
|
||||||
result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE.also {
|
|
||||||
|
|
||||||
// If the season button is visible the result season button will be next focus down
|
|
||||||
if (result_series_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
|
||||||
else
|
|
||||||
setFocusUpAndDown(result_bookmark_button, result_season_button)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_season_button?.setOnClickListener {
|
|
||||||
result_season_button?.popupMenuNoIconsAndNoStringRes(
|
|
||||||
items = seasonList
|
|
||||||
.map { (name, season) ->
|
|
||||||
Pair(
|
|
||||||
season ?: -2,
|
|
||||||
name ?: fromIndexToSeasonText(season)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
val id = this.itemId
|
|
||||||
|
|
||||||
viewModel.changeSeason(if (id == -2) null else id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.also {
|
|
||||||
|
|
||||||
// If Season button is invisible then the bookmark button next focus is episode select
|
|
||||||
if (result_season_button?.isVisible != true) {
|
|
||||||
if (result_series_parent?.isVisible == true)
|
|
||||||
setFocusUpAndDown(result_resume_series_button, result_episode_select)
|
|
||||||
else
|
|
||||||
setFocusUpAndDown(result_bookmark_button, result_episode_select)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||||
|
@ -1546,6 +1436,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
observe(viewModel.episodes) { episodeList ->
|
observe(viewModel.episodes) { episodeList ->
|
||||||
lateFixDownloadButton(episodeList.size <= 1) // movies can have multible parts but still be *movies* this will fix this
|
lateFixDownloadButton(episodeList.size <= 1) // movies can have multible parts but still be *movies* this will fix this
|
||||||
var isSeriesVisible = false
|
var isSeriesVisible = false
|
||||||
|
@ -1666,7 +1557,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
startAction = null
|
startAction = null
|
||||||
startValue = null
|
startValue = null
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
observe(viewModel.episodes) { episodes ->
|
observe(viewModel.episodes) { episodes ->
|
||||||
when (episodes) {
|
when (episodes) {
|
||||||
is Resource.Failure -> {
|
is Resource.Failure -> {
|
||||||
|
@ -1689,20 +1580,21 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.dubStatus) { status ->
|
observe(viewModel.selectedSeason) { text ->
|
||||||
result_dub_select?.apply {
|
result_season_button?.setText(text)
|
||||||
isVisible = status != null
|
|
||||||
status?.toString()?.let {
|
// If the season button is visible the result season button will be next focus down
|
||||||
text = it
|
if (result_season_button?.isVisible == true)
|
||||||
}
|
if (result_series_parent?.isVisible == true)
|
||||||
}
|
setFocusUpAndDown(result_resume_series_button, result_season_button)
|
||||||
|
else
|
||||||
|
setFocusUpAndDown(result_bookmark_button, result_season_button)
|
||||||
}
|
}
|
||||||
|
|
||||||
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
observe(viewModel.selectedDubStatus) { status ->
|
||||||
|
result_dub_select?.setText(status)
|
||||||
observe(viewModel.dubSubSelections) { range ->
|
|
||||||
result_dub_select?.visibility = if (range.size <= 1) GONE else VISIBLE
|
|
||||||
|
|
||||||
|
if (result_dub_select?.isVisible == true)
|
||||||
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
if (result_season_button?.isVisible != true && result_episode_select?.isVisible != true) {
|
||||||
if (result_series_parent?.isVisible == true)
|
if (result_series_parent?.isVisible == true)
|
||||||
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
setFocusUpAndDown(result_resume_series_button, result_dub_select)
|
||||||
|
@ -1711,53 +1603,90 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
observe(viewModel.selectedRange) { range ->
|
||||||
// Always escape focus
|
result_episode_select.setText(range)
|
||||||
if (hasFocus) result_bookmark_button?.requestFocus()
|
|
||||||
|
// If Season button is invisible then the bookmark button next focus is episode select
|
||||||
|
if (result_episode_select?.isVisible == true)
|
||||||
|
if (result_season_button?.isVisible != true) {
|
||||||
|
if (result_series_parent?.isVisible == true)
|
||||||
|
setFocusUpAndDown(result_resume_series_button, result_episode_select)
|
||||||
|
else
|
||||||
|
setFocusUpAndDown(result_bookmark_button, result_episode_select)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_dub_select.setOnClickListener {
|
// val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true
|
||||||
val ranges = dubRange
|
|
||||||
if (ranges != null) {
|
observe(viewModel.dubSubSelections) { range ->
|
||||||
it.popupMenuNoIconsAndNoStringRes(ranges
|
result_dub_select.setOnClickListener { view ->
|
||||||
.map { status ->
|
view?.context?.let { ctx ->
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(range
|
||||||
|
.mapNotNull { (text, status) ->
|
||||||
Pair(
|
Pair(
|
||||||
status.ordinal,
|
status.ordinal,
|
||||||
status.toString()
|
text?.asStringNull(ctx) ?: return@mapNotNull null
|
||||||
)
|
)
|
||||||
}
|
}) {
|
||||||
.toList()) {
|
|
||||||
viewModel.changeDubStatus(DubStatus.values()[itemId])
|
viewModel.changeDubStatus(DubStatus.values()[itemId])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result_episode_select?.setOnClickListener {
|
observe(viewModel.rangeSelections) { range ->
|
||||||
val ranges = episodeRanges
|
result_episode_select.setOnClickListener { view ->
|
||||||
if (ranges != null) {
|
view?.context?.let { ctx ->
|
||||||
it.popupMenuNoIconsAndNoStringRes(ranges.mapIndexed { index, s -> Pair(index, s) }
|
val names = range
|
||||||
.toList()) {
|
.mapNotNull { (text, r) ->
|
||||||
viewModel.changeRange(itemId)
|
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
||||||
|
index to name
|
||||||
|
}) {
|
||||||
|
viewModel.changeRange(names[itemId].first)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.seasonSelections) { seasonList ->
|
||||||
|
result_season_button?.setOnClickListener { view ->
|
||||||
|
view?.context?.let { ctx ->
|
||||||
|
val names = seasonList
|
||||||
|
.mapNotNull { (text, r) ->
|
||||||
|
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
||||||
|
index to name
|
||||||
|
}) {
|
||||||
|
viewModel.changeSeason(names[itemId].first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
||||||
|
// Always escape focus
|
||||||
|
if (hasFocus) result_bookmark_button?.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
result_sync_set_score?.setOnClickListener {
|
result_sync_set_score?.setOnClickListener {
|
||||||
syncModel.publishUserData()
|
syncModel.publishUserData()
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.episodesCount) { count ->
|
observe(viewModel.episodesCountText) { count ->
|
||||||
if (count < 0) {
|
result_episodes_text.setText(count)
|
||||||
result_episodes_text?.isVisible = false
|
|
||||||
} else {
|
|
||||||
// result_episodes_text?.isVisible = true
|
|
||||||
result_episodes_text?.text =
|
|
||||||
"$count ${if (count == 1) getString(R.string.episode) else getString(R.string.episodes)}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.id) {
|
observe(viewModel.trailers) { trailers ->
|
||||||
currentId = it
|
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(viewModel.recommendations) { recommendations ->
|
||||||
|
setRecommendations(recommendations, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.page) { data ->
|
observe(viewModel.page) { data ->
|
||||||
|
@ -1778,17 +1707,11 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_meta_rating.setText(d.ratingText)
|
result_meta_rating.setText(d.ratingText)
|
||||||
result_description.setTextHtml(d.plotText)
|
result_description.setTextHtml(d.plotText)
|
||||||
result_cast_text.setText(d.actorsText)
|
result_cast_text.setText(d.actorsText)
|
||||||
setRecommendations.setText(d.nextAiringEpisode)
|
result_next_airing.setText(d.nextAiringEpisode)
|
||||||
result_next_airing_time.setText(d.nextAiringDate)
|
result_next_airing_time.setText(d.nextAiringDate)
|
||||||
|
|
||||||
result_poster.setImage(d.posterImage)
|
result_poster.setImage(d.posterImage)
|
||||||
|
|
||||||
if(!d.posterUrl.isNullOrBlank()) {
|
|
||||||
result_poster?.setImage(d.posterUrl, d.posterHeaders)
|
|
||||||
} else {
|
|
||||||
result_poster?.setImageResource(R.drawable.default_cover)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
result_cast_items?.isVisible = d.actors != null
|
result_cast_items?.isVisible = d.actors != null
|
||||||
(result_cast_items?.adapter as ActorAdaptor?)?.apply {
|
(result_cast_items?.adapter as ActorAdaptor?)?.apply {
|
||||||
|
@ -1821,11 +1744,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecommendations(d.recommendations, null)
|
|
||||||
setActors(d.actors)
|
|
||||||
setNextEpisode(if (d is EpisodeResponse) d.nextAiring else null)
|
|
||||||
setTrailers(d.trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
|
||||||
|
|
||||||
if (syncModel.addSyncs(d.syncData)) {
|
if (syncModel.addSyncs(d.syncData)) {
|
||||||
syncModel.updateMetaAndUser()
|
syncModel.updateMetaAndUser()
|
||||||
syncModel.updateSynced()
|
syncModel.updateSynced()
|
||||||
|
@ -1833,70 +1751,20 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
syncModel.addFromUrl(d.url)
|
syncModel.addFromUrl(d.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
result_meta_site?.text = d.apiName
|
result_play_movie.setText(d.playMovieText)
|
||||||
val posterImageLink = d.posterUrl
|
|
||||||
if (!posterImageLink.isNullOrEmpty()) {
|
|
||||||
|
|
||||||
//result_poster_blur?.setImageBlur(posterImageLink, 10, 3, d.posterHeaders)
|
result_description?.setOnClickListener { view ->
|
||||||
//Full screen view of Poster image
|
view.context?.let { ctx ->
|
||||||
if (context?.isTrueTvSettings() == false) // Poster not clickable on tv
|
|
||||||
result_poster_holder?.setOnClickListener {
|
|
||||||
try {
|
|
||||||
context?.let { ctx ->
|
|
||||||
runBlocking {
|
|
||||||
val sourceBuilder = AlertDialog.Builder(ctx)
|
|
||||||
sourceBuilder.setView(R.layout.result_poster)
|
|
||||||
|
|
||||||
val sourceDialog = sourceBuilder.create()
|
|
||||||
sourceDialog.show()
|
|
||||||
|
|
||||||
sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
|
|
||||||
?.apply {
|
|
||||||
setImage(posterImageLink)
|
|
||||||
setOnClickListener {
|
|
||||||
sourceDialog.dismissSafe()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result_poster?.setImageResource(R.drawable.default_cover)
|
|
||||||
//result_poster_blur?.setImageResource(R.drawable.default_cover)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_poster_holder?.visibility = VISIBLE
|
|
||||||
|
|
||||||
result_play_movie?.text =
|
|
||||||
if (d.typeText == TvType.Live) getString(R.string.play_livestream_button) else getString(
|
|
||||||
R.string.play_movie_button
|
|
||||||
)
|
|
||||||
//result_plot_header?.text =
|
|
||||||
// if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot)
|
|
||||||
val syno = d.plot
|
|
||||||
if (!syno.isNullOrEmpty()) {
|
|
||||||
result_description?.setOnClickListener {
|
|
||||||
val builder: AlertDialog.Builder =
|
val builder: AlertDialog.Builder =
|
||||||
AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||||
builder.setMessage(syno.html())
|
builder.setMessage(d.plotText.asString(ctx).html())
|
||||||
.setTitle(if (d.typeText == TvType.Torrent) R.string.torrent_plot else R.string.result_plot)
|
.setTitle(d.plotHeaderText.asString(ctx))
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
result_description?.text = syno.html()
|
|
||||||
} else {
|
|
||||||
result_description?.text =
|
|
||||||
if (d.typeText == TvType.Torrent) getString(R.string.torrent_no_plot) else getString(
|
|
||||||
R.string.normal_no_plot
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_tag?.removeAllViews()
|
result_tag?.removeAllViews()
|
||||||
//result_tag_holder?.visibility = GONE
|
|
||||||
// result_status.visibility = GONE
|
|
||||||
|
|
||||||
d.comingSoon.let { soon ->
|
d.comingSoon.let { soon ->
|
||||||
result_coming_soon?.isVisible = soon
|
result_coming_soon?.isVisible = soon
|
||||||
|
@ -1918,6 +1786,8 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO FIX
|
||||||
|
/*
|
||||||
if (d.typeText.isMovieType()) {
|
if (d.typeText.isMovieType()) {
|
||||||
val hasDownloadSupport = api.hasDownloadSupport
|
val hasDownloadSupport = api.hasDownloadSupport
|
||||||
lateFixDownloadButton(true)
|
lateFixDownloadButton(true)
|
||||||
|
@ -1942,11 +1812,6 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
// result_options.setOnClickListener {
|
|
||||||
// val card = currentEpisodes?.first() ?: return@setOnClickListener
|
|
||||||
// handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
|
||||||
// }
|
|
||||||
|
|
||||||
result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport
|
result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport
|
||||||
if (hasDownloadSupport) {
|
if (hasDownloadSupport) {
|
||||||
val localId = d.getId()
|
val localId = d.getId()
|
||||||
|
@ -2045,19 +1910,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
} else {
|
} else {
|
||||||
lateFixDownloadButton(false)
|
lateFixDownloadButton(false)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
when (d) {
|
|
||||||
is AnimeLoadResponse -> {
|
|
||||||
|
|
||||||
// val preferEnglish = true
|
|
||||||
//val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name
|
|
||||||
val titleName = d.name
|
|
||||||
result_title.text = titleName
|
|
||||||
//result_toolbar.title = titleName
|
|
||||||
}
|
|
||||||
else -> result_title.text = d.name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is Resource.Failure -> {
|
is Resource.Failure -> {
|
||||||
result_error_text.text = url?.plus("\n") + data.errorString
|
result_error_text.text = url?.plus("\n") + data.errorString
|
||||||
|
@ -2091,7 +1944,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
val tempUrl = url
|
val tempUrl = url
|
||||||
if (tempUrl != null) {
|
if (tempUrl != null) {
|
||||||
result_reload_connectionerror.setOnClickListener {
|
result_reload_connectionerror.setOnClickListener {
|
||||||
viewModel.load(tempUrl, apiName, showFillers)
|
viewModel.load(tempUrl, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
|
||||||
}
|
}
|
||||||
|
|
||||||
result_reload_connection_open_in_browser?.setOnClickListener {
|
result_reload_connection_open_in_browser?.setOnClickListener {
|
||||||
|
@ -2124,9 +1977,9 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
result_meta_site?.isFocusable = false
|
result_meta_site?.isFocusable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restart || viewModel.result.value == null) {
|
if (restart || !viewModel.hasLoaded()) {
|
||||||
//viewModel.clear()
|
//viewModel.clear()
|
||||||
viewModel.load(tempUrl, apiName, showFillers)
|
viewModel.load(tempUrl, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
@ -7,16 +8,18 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.getAniListId
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId
|
||||||
import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider
|
import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider
|
||||||
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider
|
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider
|
||||||
import com.lagradost.cloudstream3.metaproviders.SyncRedirector
|
import com.lagradost.cloudstream3.metaproviders.SyncRedirector
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.player.IGenerator
|
import com.lagradost.cloudstream3.ui.player.IGenerator
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
|
||||||
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@ -55,8 +58,20 @@ data class ResultData(
|
||||||
val yearText: UiText?,
|
val yearText: UiText?,
|
||||||
val nextAiringDate: UiText?,
|
val nextAiringDate: UiText?,
|
||||||
val nextAiringEpisode: UiText?,
|
val nextAiringEpisode: UiText?,
|
||||||
|
val playMovieText: UiText?,
|
||||||
|
val plotHeaderText: UiText,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun txt(status: DubStatus?): UiText? {
|
||||||
|
return txt(
|
||||||
|
when (status) {
|
||||||
|
DubStatus.Dubbed -> R.string.app_dubbed_text
|
||||||
|
DubStatus.Subbed -> R.string.app_subbed_text
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun LoadResponse.toResultData(repo: APIRepository): ResultData {
|
fun LoadResponse.toResultData(repo: APIRepository): ResultData {
|
||||||
debugAssert({ repo.name == apiName }) {
|
debugAssert({ repo.name == apiName }) {
|
||||||
"Api returned wrong apiName"
|
"Api returned wrong apiName"
|
||||||
|
@ -101,6 +116,20 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultData(
|
return ResultData(
|
||||||
|
plotHeaderText = txt(
|
||||||
|
when (this.type) {
|
||||||
|
TvType.Torrent -> R.string.torrent_plot
|
||||||
|
else -> R.string.result_plot
|
||||||
|
}
|
||||||
|
),
|
||||||
|
playMovieText = txt(
|
||||||
|
when (this.type) {
|
||||||
|
TvType.Live -> R.string.play_livestream_button
|
||||||
|
TvType.Torrent -> R.string.play_torrent_button
|
||||||
|
TvType.Movie, TvType.AnimeMovie -> R.string.play_movie_button
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
),
|
||||||
nextAiringDate = nextAiringDate,
|
nextAiringDate = nextAiringDate,
|
||||||
nextAiringEpisode = nextAiringEpisode,
|
nextAiringEpisode = nextAiringEpisode,
|
||||||
posterImage = img(
|
posterImage = img(
|
||||||
|
@ -174,6 +203,8 @@ class ResultViewModel2 : ViewModel() {
|
||||||
/** map<dub, map<season, List<episode>>> */
|
/** map<dub, map<season, List<episode>>> */
|
||||||
private var currentEpisodes: Map<EpisodeIndexer, List<ResultEpisode>> = mapOf()
|
private var currentEpisodes: Map<EpisodeIndexer, List<ResultEpisode>> = mapOf()
|
||||||
private var currentRanges: Map<EpisodeIndexer, List<EpisodeRange>> = mapOf()
|
private var currentRanges: Map<EpisodeIndexer, List<EpisodeRange>> = mapOf()
|
||||||
|
private var currentMeta: SyncAPI.SyncResult? = null
|
||||||
|
private var currentSync: Map<String, String>? = null
|
||||||
private var currentIndex: EpisodeIndexer? = null
|
private var currentIndex: EpisodeIndexer? = null
|
||||||
private var currentRange: EpisodeRange? = null
|
private var currentRange: EpisodeRange? = null
|
||||||
private var currentShowFillers: Boolean = false
|
private var currentShowFillers: Boolean = false
|
||||||
|
@ -193,20 +224,42 @@ class ResultViewModel2 : ViewModel() {
|
||||||
MutableLiveData(Resource.Loading())
|
MutableLiveData(Resource.Loading())
|
||||||
val episodes: LiveData<Resource<List<ResultEpisode>>> = _episodes
|
val episodes: LiveData<Resource<List<ResultEpisode>>> = _episodes
|
||||||
|
|
||||||
private val _episodesCount: MutableLiveData<Int> =
|
private val _episodesCountText: MutableLiveData<UiText?> =
|
||||||
MutableLiveData(0)
|
MutableLiveData(null)
|
||||||
val episodesCount: LiveData<Int> = _episodesCount
|
val episodesCountText: LiveData<UiText?> = _episodesCountText
|
||||||
|
|
||||||
private val _trailers: MutableLiveData<List<TrailerData>> = MutableLiveData(mutableListOf())
|
private val _trailers: MutableLiveData<List<TrailerData>> = MutableLiveData(mutableListOf())
|
||||||
val trailers: LiveData<List<TrailerData>> = _trailers
|
val trailers: LiveData<List<TrailerData>> = _trailers
|
||||||
|
|
||||||
private val _dubStatus: MutableLiveData<DubStatus?> = MutableLiveData(null)
|
|
||||||
val dubStatus: LiveData<DubStatus?> = _dubStatus
|
|
||||||
|
|
||||||
private val _dubSubSelections: MutableLiveData<List<DubStatus>> = MutableLiveData(emptyList())
|
private val _dubSubSelections: MutableLiveData<List<Pair<UiText?, DubStatus>>> =
|
||||||
val dubSubSelections: LiveData<List<DubStatus>> = _dubSubSelections
|
MutableLiveData(emptyList())
|
||||||
|
val dubSubSelections: LiveData<List<Pair<UiText?, DubStatus>>> = _dubSubSelections
|
||||||
|
|
||||||
|
private val _rangeSelections: MutableLiveData<List<Pair<UiText?, EpisodeRange>>> = MutableLiveData(emptyList())
|
||||||
|
val rangeSelections: LiveData<List<Pair<UiText?, EpisodeRange>>> = _rangeSelections
|
||||||
|
|
||||||
|
private val _seasonSelections: MutableLiveData<List<Pair<UiText?, Int>>> = MutableLiveData(emptyList())
|
||||||
|
val seasonSelections: LiveData<List<Pair<UiText?, Int>>> = _seasonSelections
|
||||||
|
|
||||||
|
|
||||||
|
private val _recommendations: MutableLiveData<List<SearchResponse>> =
|
||||||
|
MutableLiveData(emptyList())
|
||||||
|
val recommendations: LiveData<List<SearchResponse>> = _recommendations
|
||||||
|
|
||||||
|
private val _selectedRange: MutableLiveData<UiText?> =
|
||||||
|
MutableLiveData(null)
|
||||||
|
val selectedRange: LiveData<UiText?> = _selectedRange
|
||||||
|
|
||||||
|
private val _selectedSeason: MutableLiveData<UiText?> =
|
||||||
|
MutableLiveData(null)
|
||||||
|
val selectedSeason: LiveData<UiText?> = _selectedSeason
|
||||||
|
|
||||||
|
private val _selectedDubStatus: MutableLiveData<UiText?> = MutableLiveData(null)
|
||||||
|
val selectedDubStatus: LiveData<UiText?> = _selectedDubStatus
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val TAG = "RVM2"
|
||||||
private const val EPISODE_RANGE_SIZE = 50
|
private const val EPISODE_RANGE_SIZE = 50
|
||||||
private const val EPISODE_RANGE_OVERLOAD = 60
|
private const val EPISODE_RANGE_OVERLOAD = 60
|
||||||
|
|
||||||
|
@ -324,6 +377,102 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun applyMeta(
|
||||||
|
resp: LoadResponse,
|
||||||
|
meta: SyncAPI.SyncResult?,
|
||||||
|
syncs: Map<String, String>? = null
|
||||||
|
): Pair<LoadResponse, Boolean> {
|
||||||
|
if (meta == null) return resp to false
|
||||||
|
var updateEpisodes = false
|
||||||
|
val out = resp.apply {
|
||||||
|
Log.i(ResultViewModel.TAG, "applyMeta")
|
||||||
|
|
||||||
|
duration = duration ?: meta.duration
|
||||||
|
rating = rating ?: meta.publicScore
|
||||||
|
tags = tags ?: meta.genres
|
||||||
|
plot = if (plot.isNullOrBlank()) meta.synopsis else plot
|
||||||
|
posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl
|
||||||
|
actors = actors ?: meta.actors
|
||||||
|
|
||||||
|
if (this is EpisodeResponse) {
|
||||||
|
nextAiring = nextAiring ?: meta.nextAiring
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((k, v) in syncs ?: emptyMap()) {
|
||||||
|
syncData[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
val realRecommendations = ArrayList<SearchResponse>()
|
||||||
|
val apiNames = listOf(GogoanimeProvider().name, NineAnimeProvider().name)
|
||||||
|
meta.recommendations?.forEach { rec ->
|
||||||
|
apiNames.forEach { name ->
|
||||||
|
realRecommendations.add(rec.copy(apiName = name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recommendations = recommendations?.union(realRecommendations)?.toList()
|
||||||
|
?: realRecommendations
|
||||||
|
|
||||||
|
argamap({
|
||||||
|
addTrailer(meta.trailers)
|
||||||
|
}, {
|
||||||
|
if (this !is AnimeLoadResponse) return@argamap
|
||||||
|
val map =
|
||||||
|
Kitsu.getEpisodesDetails(getMalId(), getAniListId(), isResponseRequired = false)
|
||||||
|
if (map.isNullOrEmpty()) return@argamap
|
||||||
|
updateEpisodes = DubStatus.values().map { dubStatus ->
|
||||||
|
val current =
|
||||||
|
this.episodes[dubStatus]?.mapIndexed { index, episode ->
|
||||||
|
episode.apply {
|
||||||
|
this.episode = this.episode ?: (index + 1)
|
||||||
|
}
|
||||||
|
}?.sortedBy { it.episode ?: 0 }?.toMutableList()
|
||||||
|
if (current.isNullOrEmpty()) return@map false
|
||||||
|
val episodeNumbers = current.map { ep -> ep.episode!! }
|
||||||
|
var updateCount = 0
|
||||||
|
map.forEach { (episode, node) ->
|
||||||
|
episodeNumbers.binarySearch(episode).let { index ->
|
||||||
|
current.getOrNull(index)?.let { currentEp ->
|
||||||
|
current[index] = currentEp.apply {
|
||||||
|
updateCount++
|
||||||
|
val currentBack = this
|
||||||
|
this.description = this.description ?: node.description?.en
|
||||||
|
this.name = this.name ?: node.titles?.canonical
|
||||||
|
this.episode = this.episode ?: node.num ?: episodeNumbers[index]
|
||||||
|
this.posterUrl = this.posterUrl ?: node.thumbnail?.original?.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.episodes[dubStatus] = current
|
||||||
|
updateCount > 0
|
||||||
|
}.any { it }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return out to updateEpisodes
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMeta(meta: SyncAPI.SyncResult, syncs: Map<String, String>?) =
|
||||||
|
viewModelScope.launch {
|
||||||
|
Log.i(TAG, "setMeta")
|
||||||
|
currentMeta = meta
|
||||||
|
currentSync = syncs
|
||||||
|
val (value, updateEpisodes) = Coroutines.ioWork {
|
||||||
|
currentResponse?.let { resp ->
|
||||||
|
return@ioWork applyMeta(resp, meta, syncs)
|
||||||
|
}
|
||||||
|
return@ioWork null to null
|
||||||
|
}
|
||||||
|
|
||||||
|
postSuccessful(
|
||||||
|
value ?: return@launch,
|
||||||
|
currentRepo ?: return@launch,
|
||||||
|
updateEpisodes ?: return@launch,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun updateFillers(name: String) {
|
private suspend fun updateFillers(name: String) {
|
||||||
fillers =
|
fillers =
|
||||||
try {
|
try {
|
||||||
|
@ -343,6 +492,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
postEpisodeRange(currentIndex, range)
|
postEpisodeRange(currentIndex, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun changeSeason(season: Int) {
|
||||||
|
postEpisodeRange(currentIndex?.copy(season = season), currentRange)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getEpisodes(indexer: EpisodeIndexer, range: EpisodeRange): List<ResultEpisode> {
|
private fun getEpisodes(indexer: EpisodeIndexer, range: EpisodeRange): List<ResultEpisode> {
|
||||||
//TODO ADD GENERATOR
|
//TODO ADD GENERATOR
|
||||||
|
|
||||||
|
@ -377,9 +530,34 @@ class ResultViewModel2 : ViewModel() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val size = currentEpisodes[indexer]?.size
|
||||||
|
|
||||||
|
_episodesCountText.postValue(
|
||||||
|
txt(
|
||||||
|
R.string.episode_format,
|
||||||
|
if (size == 1) R.string.episode else R.string.episodes,
|
||||||
|
size
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
currentIndex = indexer
|
currentIndex = indexer
|
||||||
currentRange = range
|
currentRange = range
|
||||||
|
|
||||||
|
_selectedSeason.postValue(
|
||||||
|
when (indexer.season) {
|
||||||
|
0 -> txt(R.string.no_season)
|
||||||
|
else -> txt(R.string.season_format, R.string.season, indexer.season) //TODO FIX
|
||||||
|
}
|
||||||
|
)
|
||||||
|
_selectedRange.postValue(
|
||||||
|
if ((currentRanges[indexer]?.size ?: 0) > 1) {
|
||||||
|
txt(R.string.episodes_range, range.startEpisode, range.endEpisode)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
_selectedDubStatus.postValue(txt(indexer.dubStatus))
|
||||||
|
|
||||||
//TODO SET KEYS
|
//TODO SET KEYS
|
||||||
preferStartEpisode = range.startEpisode
|
preferStartEpisode = range.startEpisode
|
||||||
preferStartSeason = indexer.season
|
preferStartSeason = indexer.season
|
||||||
|
@ -587,10 +765,13 @@ class ResultViewModel2 : ViewModel() {
|
||||||
|
|
||||||
// this instantly updates the metadata on the page
|
// this instantly updates the metadata on the page
|
||||||
private fun postPage(loadResponse: LoadResponse, apiRepository: APIRepository) {
|
private fun postPage(loadResponse: LoadResponse, apiRepository: APIRepository) {
|
||||||
|
_recommendations.postValue(loadResponse.recommendations ?: emptyList())
|
||||||
_page.postValue(Resource.Success(loadResponse.toResultData(apiRepository)))
|
_page.postValue(Resource.Success(loadResponse.toResultData(apiRepository)))
|
||||||
_trailers.postValue(loadResponse.trailers)
|
_trailers.postValue(loadResponse.trailers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasLoaded() = currentResponse != null
|
||||||
|
|
||||||
fun load(
|
fun load(
|
||||||
url: String,
|
url: String,
|
||||||
apiName: String,
|
apiName: String,
|
||||||
|
@ -647,7 +828,9 @@ class ResultViewModel2 : ViewModel() {
|
||||||
_page.postValue(data)
|
_page.postValue(data)
|
||||||
}
|
}
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val loadResponse = data.value
|
val loadResponse = Coroutines.ioWork {
|
||||||
|
applyMeta(data.value, currentMeta, currentSync).first
|
||||||
|
}
|
||||||
val mainId = loadResponse.getId()
|
val mainId = loadResponse.getId()
|
||||||
|
|
||||||
AcraApplication.setKey(
|
AcraApplication.setKey(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||||
|
|
||||||
|
@ -18,7 +19,12 @@ sealed class UiText {
|
||||||
) : UiText()
|
) : UiText()
|
||||||
|
|
||||||
fun asStringNull(context: Context?): String? {
|
fun asStringNull(context: Context?): String? {
|
||||||
|
try {
|
||||||
return asString(context ?: return null)
|
return asString(context ?: return null)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asString(context: Context): String {
|
fun asString(context: Context): String {
|
||||||
|
|
|
@ -290,15 +290,15 @@
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/result_poster_holder"
|
android:id="@+id/result_poster_holder"
|
||||||
android:layout_width="100dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="140dp"
|
android:layout_height="wrap_content"
|
||||||
app:cardCornerRadius="@dimen/rounded_image_radius">
|
app:cardCornerRadius="@dimen/rounded_image_radius">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/result_poster"
|
android:id="@+id/result_poster"
|
||||||
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="100dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="140dp"
|
||||||
android:contentDescription="@string/result_poster_img_des"
|
android:contentDescription="@string/result_poster_img_des"
|
||||||
android:foreground="@drawable/outline_drawable"
|
android:foreground="@drawable/outline_drawable"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
|
|
@ -286,9 +286,12 @@
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="season">Season</string>
|
<string name="season">Season</string>
|
||||||
|
<string name="season_format">%s %d</string>
|
||||||
<string name="no_season">No Season</string>
|
<string name="no_season">No Season</string>
|
||||||
<string name="episode">Episode</string>
|
<string name="episode">Episode</string>
|
||||||
<string name="episodes">Episodes</string>
|
<string name="episodes">Episodes</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="episode_format" formatted="true">%d %s</string>
|
||||||
<string name="season_short">S</string>
|
<string name="season_short">S</string>
|
||||||
<string name="episode_short">E</string>
|
<string name="episode_short">E</string>
|
||||||
<string name="no_episodes_found">No Episodes found</string>
|
<string name="no_episodes_found">No Episodes found</string>
|
||||||
|
|
Loading…
Reference in a new issue