forked from recloudstream/cloudstream
Added trailers and poster to TV
This commit is contained in:
parent
b6b7cceea5
commit
5b26c998b4
6 changed files with 176 additions and 59 deletions
|
@ -237,7 +237,6 @@ object APIHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Context.getHasTrailers(): Boolean {
|
private fun Context.getHasTrailers(): Boolean {
|
||||||
if (isTvSettings()) return false
|
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
return settingsManager.getBoolean(this.getString(R.string.show_trailers_key), true)
|
return settingsManager.getBoolean(this.getString(R.string.show_trailers_key), true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||||
|
|
||||||
|
class ExtractorLinkGenerator(
|
||||||
|
private val links: List<ExtractorLink>,
|
||||||
|
private val subtitles: List<SubtitleData>,
|
||||||
|
) : IGenerator {
|
||||||
|
override val hasCache = false
|
||||||
|
|
||||||
|
override fun getCurrentId(): Int? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAll(): List<Any>? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasPrev(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCurrent(offset: Int): Any? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun goto(index: Int) {}
|
||||||
|
|
||||||
|
override fun next() {}
|
||||||
|
|
||||||
|
override fun prev() {}
|
||||||
|
|
||||||
|
override suspend fun generateLinks(
|
||||||
|
clearCache: Boolean,
|
||||||
|
isCasting: Boolean,
|
||||||
|
callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,
|
||||||
|
subtitleCallback: (SubtitleData) -> Unit,
|
||||||
|
offset: Int
|
||||||
|
): Boolean {
|
||||||
|
subtitles.forEach(subtitleCallback)
|
||||||
|
links.forEach {
|
||||||
|
callback.invoke(it to null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,8 @@ import kotlinx.android.synthetic.main.fragment_result.result_next_airing
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_next_airing_time
|
import kotlinx.android.synthetic.main.fragment_result.result_next_airing_time
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_no_episodes
|
import kotlinx.android.synthetic.main.fragment_result.result_no_episodes
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_play_movie
|
import kotlinx.android.synthetic.main.fragment_result.result_play_movie
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_poster
|
||||||
|
import kotlinx.android.synthetic.main.fragment_result.result_poster_holder
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_reload_connection_open_in_browser
|
import kotlinx.android.synthetic.main.fragment_result.result_reload_connection_open_in_browser
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_reload_connectionerror
|
import kotlinx.android.synthetic.main.fragment_result.result_reload_connectionerror
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_resume_parent
|
import kotlinx.android.synthetic.main.fragment_result.result_resume_parent
|
||||||
|
|
|
@ -3,30 +3,28 @@ package com.lagradost.cloudstream3.ui.result
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
import com.lagradost.cloudstream3.DubStatus
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
import com.lagradost.cloudstream3.mvvm.ResourceSome
|
import com.lagradost.cloudstream3.mvvm.ResourceSome
|
||||||
import com.lagradost.cloudstream3.mvvm.Some
|
import com.lagradost.cloudstream3.mvvm.Some
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
|
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||||
|
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.setMaxViewPoolSize
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.result_episodes
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.result_episodes_text
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.result_play_movie
|
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.result_root
|
|
||||||
|
|
||||||
class ResultFragmentTv : ResultFragment() {
|
class ResultFragmentTv : ResultFragment() {
|
||||||
override val resultLayout = R.layout.fragment_result_tv
|
override val resultLayout = R.layout.fragment_result_tv
|
||||||
|
@ -85,6 +83,24 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||||
|
context?.updateHasTrailers()
|
||||||
|
if (!LoadResponse.isTrailersEnabled) return
|
||||||
|
|
||||||
|
result_play_trailer?.isGone = trailers.isNullOrEmpty()
|
||||||
|
result_play_trailer?.setOnClickListener {
|
||||||
|
if (trailers.isNullOrEmpty()) return@setOnClickListener
|
||||||
|
activity.navigate(
|
||||||
|
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||||
|
ExtractorLinkGenerator(
|
||||||
|
trailers,
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
currentRecommendations = rec ?: emptyList()
|
currentRecommendations = rec ?: emptyList()
|
||||||
val isInvalid = rec.isNullOrEmpty()
|
val isInvalid = rec.isNullOrEmpty()
|
||||||
|
@ -110,7 +126,7 @@ class ResultFragmentTv : ResultFragment() {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
result_episodes?.layoutManager =
|
result_episodes?.layoutManager =
|
||||||
//LinearListLayout(result_episodes ?: return, result_episodes?.context).apply {
|
//LinearListLayout(result_episodes ?: return, result_episodes?.context).apply {
|
||||||
LinearListLayout(result_episodes?.context).apply {
|
LinearListLayout(result_episodes?.context).apply {
|
||||||
setHorizontal()
|
setHorizontal()
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,61 +227,91 @@
|
||||||
tools:text="The Perfect Run The Perfect Run" />
|
tools:text="The Perfect Run The Perfect Run" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
<com.lagradost.cloudstream3.widget.FlowLayout
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:itemSpacing="10dp">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/result_meta_site"
|
android:id="@+id/result_poster_holder"
|
||||||
style="@style/SmallBlackButton"
|
android:layout_width="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_height="wrap_content"
|
||||||
tools:text="Gogoanime" />
|
android:layout_marginEnd="10dp"
|
||||||
|
app:cardCornerRadius="@dimen/rounded_image_radius">
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/result_meta_type"
|
android:id="@+id/result_poster"
|
||||||
style="@style/ResultInfoText"
|
android:layout_width="100dp"
|
||||||
tools:text="Movie" />
|
android:layout_height="140dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:contentDescription="@string/result_poster_img_des"
|
||||||
|
android:foreground="@drawable/outline_drawable"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:src="@drawable/example_poster" />
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/result_meta_year"
|
android:layout_width="match_parent"
|
||||||
style="@style/ResultInfoText"
|
android:layout_height="match_parent"
|
||||||
tools:text="2022" />
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||||
android:id="@+id/result_meta_rating"
|
android:layout_width="match_parent"
|
||||||
style="@style/ResultInfoText"
|
android:layout_height="wrap_content"
|
||||||
tools:text="Rated: 8.5/10.0" />
|
app:itemSpacing="10dp">
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/result_meta_status"
|
android:id="@+id/result_meta_site"
|
||||||
style="@style/ResultInfoText"
|
style="@style/SmallBlackButton"
|
||||||
tools:text="Ongoing" />
|
android:layout_gravity="center_vertical"
|
||||||
|
tools:text="Gogoanime" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_type"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Movie" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_year"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="2022" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_rating"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Rated: 8.5/10.0" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_status"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="Ongoing" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_meta_duration"
|
||||||
|
style="@style/ResultInfoText"
|
||||||
|
tools:text="121min" />
|
||||||
|
</com.lagradost.cloudstream3.widget.FlowLayout>
|
||||||
|
<!--
|
||||||
|
This has half margin and half padding to make TV focus on description look better.
|
||||||
|
The focus outline now settles between the poster and text.
|
||||||
|
-->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:foreground="@drawable/outline_drawable"
|
||||||
|
android:maxLength="1000"
|
||||||
|
android:nextFocusUp="@id/result_back"
|
||||||
|
android:nextFocusDown="@id/result_play_movie"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_meta_duration"
|
|
||||||
style="@style/ResultInfoText"
|
|
||||||
tools:text="121min" />
|
|
||||||
</com.lagradost.cloudstream3.widget.FlowLayout>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
This has half margin and half padding to make TV focus on description look better.
|
|
||||||
The focus outline now settles between the poster and text.
|
|
||||||
-->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_description"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:foreground="@drawable/outline_drawable"
|
|
||||||
android:maxLength="1000"
|
|
||||||
android:nextFocusUp="@id/result_back"
|
|
||||||
android:nextFocusDown="@id/result_play_movie"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textColor="?attr/textColor"
|
|
||||||
android:textSize="15sp"
|
|
||||||
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -354,7 +384,7 @@
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/result_tag"
|
android:id="@+id/result_tag"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
@ -392,6 +422,7 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
android:id="@+id/result_movie_parent"
|
android:id="@+id/result_movie_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -409,7 +440,7 @@
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:minWidth="250dp"
|
android:minWidth="250dp"
|
||||||
android:nextFocusRight="@id/result_download_movie"
|
android:nextFocusRight="@id/result_play_trailer"
|
||||||
android:nextFocusUp="@id/result_cast_items"
|
android:nextFocusUp="@id/result_cast_items"
|
||||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||||
android:text="@string/play_movie_button"
|
android:text="@string/play_movie_button"
|
||||||
|
@ -418,6 +449,22 @@
|
||||||
|
|
||||||
</com.google.android.material.button.MaterialButton>
|
</com.google.android.material.button.MaterialButton>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_play_trailer"
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:minWidth="250dp"
|
||||||
|
android:nextFocusUp="@id/result_cast_items"
|
||||||
|
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||||
|
android:text="@string/play_trailer_button"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/ic_baseline_play_arrow_24">
|
||||||
|
|
||||||
|
</com.google.android.material.button.MaterialButton>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/result_movie_progress_downloaded_holder"
|
android:id="@+id/result_movie_progress_downloaded_holder"
|
||||||
|
@ -440,7 +487,7 @@
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:nextFocusLeft="@id/result_play_movie"
|
android:nextFocusLeft="@id/result_play_trailer"
|
||||||
android:nextFocusUp="@id/result_cast_items"
|
android:nextFocusUp="@id/result_cast_items"
|
||||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@
|
||||||
<string name="type_none">None</string>
|
<string name="type_none">None</string>
|
||||||
<string name="type_re_watching">Rewatching</string>
|
<string name="type_re_watching">Rewatching</string>
|
||||||
<string name="play_movie_button">Play Movie</string>
|
<string name="play_movie_button">Play Movie</string>
|
||||||
|
<string name="play_trailer_button">Play Trailer</string>
|
||||||
<string name="play_livestream_button">Play Livestream</string>
|
<string name="play_livestream_button">Play Livestream</string>
|
||||||
<string name="play_torrent_button">Stream Torrent</string>
|
<string name="play_torrent_button">Stream Torrent</string>
|
||||||
<string name="pick_source">Sources</string>
|
<string name="pick_source">Sources</string>
|
||||||
|
|
Loading…
Reference in a new issue