Added Eja.tv (live tv from all over the world)

This commit is contained in:
Blatzar 2022-07-19 22:24:55 +02:00
parent 36b30c289a
commit b5cfc2db1c
11 changed files with 416 additions and 206 deletions

View file

@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.lagradost.cloudstream3.animeproviders.* import com.lagradost.cloudstream3.animeproviders.*
import com.lagradost.cloudstream3.liveproviders.EjaTv
import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider
import com.lagradost.cloudstream3.movieproviders.* import com.lagradost.cloudstream3.movieproviders.*
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -65,6 +66,7 @@ object APIHolder {
FrenchStreamProvider(), FrenchStreamProvider(),
AsianLoadProvider(), AsianLoadProvider(),
AsiaFlixProvider(), // This should be removed in favor of asianembed.io, same source AsiaFlixProvider(), // This should be removed in favor of asianembed.io, same source
EjaTv(),
BflixProvider(), BflixProvider(),
FmoviesToProvider(), FmoviesToProvider(),
SflixProProvider(), SflixProProvider(),
@ -600,11 +602,16 @@ enum class TvType {
Torrent, Torrent,
Documentary, Documentary,
AsianDrama, AsianDrama,
Live,
} }
// IN CASE OF FUTURE ANIME MOVIE OR SMTH // IN CASE OF FUTURE ANIME MOVIE OR SMTH
fun TvType.isMovieType(): Boolean { fun TvType.isMovieType(): Boolean {
return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent || this == TvType.Live
}
fun TvType.isLiveStream(): Boolean {
return this == TvType.Live
} }
// returns if the type has an anime opening // returns if the type has an anime opening
@ -1117,6 +1124,28 @@ suspend fun MainAPI.newAnimeLoadResponse(
return builder return builder
} }
data class LiveStreamLoadResponse(
override var name: String,
override var url: String,
override var apiName: String,
var dataUrl: String,
override var posterUrl: String? = null,
override var year: Int? = null,
override var plot: String? = null,
override var type: TvType = TvType.Live,
override var rating: Int? = null,
override var tags: List<String>? = null,
override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null,
override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
) : LoadResponse
data class MovieLoadResponse( data class MovieLoadResponse(
override var name: String, override var name: String,
override var url: String, override var url: String,

View file

@ -0,0 +1,119 @@
package com.lagradost.cloudstream3.liveproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
class EjaTv : MainAPI() {
override var mainUrl = "https://eja.tv/"
override var name = "Eja.tv"
// Universal language?
override var lang = "en"
override val hasDownloadSupport = false
override val hasMainPage = true
override val supportedTypes = setOf(
TvType.Live
)
private fun Element.toSearchResponse(): MovieSearchResponse? {
val link = this.select("div.alternative a").last() ?: return null
val href = fixUrl(link.attr("href"))
val img = this.select("div.thumb img")
return MovieSearchResponse(
// Kinda hack way to get the title
img.attr("alt").replaceFirst("Watch ", ""),
href,
this@EjaTv.name,
TvType.Live,
fixUrl(img.attr("src"))
)
}
override suspend fun getMainPage(): HomePageResponse {
// Maybe this based on app language or as setting?
val language = "English"
val dataMap = mapOf(
"News" to mapOf("language" to language, "category" to "News"),
"Sports" to mapOf("language" to language, "category" to "Sports"),
"Entertainment" to mapOf("language" to language, "category" to "Entertainment")
)
return HomePageResponse(dataMap.apmap { (title, data) ->
val document = app.post(mainUrl, data = data).document
val shows = document.select("div.card-body").mapNotNull {
it.toSearchResponse()
}
HomePageList(
title,
shows
)
})
}
override suspend fun search(query: String): List<SearchResponse> {
return app.post(
mainUrl, data = mapOf("search" to query)
).document.select("div.card-body").mapNotNull {
it.toSearchResponse()
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val sections =
doc.select("li.list-group-item.d-flex.justify-content-between.align-items-center")
val link = fixUrl(sections.last()!!.select("a").attr("href"))
val title = doc.select("h5.text-center").text()
val poster = fixUrl(doc.select("p.text-center img").attr("src"))
val summary = sections.subList(0, 3).joinToString("<br>") {
val innerText = it.ownText().trim()
val outerText = it.select("a").text().trim()
"$innerText: $outerText"
}
return LiveStreamLoadResponse(
title,
url,
this.name,
LoadData(link, title).toJson(),
poster,
plot = summary
)
}
data class LoadData(
val url: String,
val title: String
)
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val loadData = parseJson<LoadData>(data)
callback.invoke(
ExtractorLink(
this.name,
loadData.title,
loadData.url,
"",
Qualities.Unknown.value,
isM3u8 = true
)
)
return true
}
}

View file

@ -164,6 +164,7 @@ class HomeFragment : Fragment() {
docs: MaterialButton?, docs: MaterialButton?,
movies: MaterialButton?, movies: MaterialButton?,
asian: MaterialButton?, asian: MaterialButton?,
livestream: MaterialButton?,
): List<Pair<MaterialButton?, List<TvType>>> { ): List<Pair<MaterialButton?, List<TvType>>> {
return listOf( return listOf(
Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)), Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)),
@ -172,6 +173,7 @@ class HomeFragment : Fragment() {
Pair(docs, listOf(TvType.Documentary)), Pair(docs, listOf(TvType.Documentary)),
Pair(movies, listOf(TvType.Movie, TvType.Torrent)), Pair(movies, listOf(TvType.Movie, TvType.Torrent)),
Pair(asian, listOf(TvType.AsianDrama)), Pair(asian, listOf(TvType.AsianDrama)),
Pair(livestream, listOf(TvType.Live)),
) )
} }
@ -205,10 +207,11 @@ class HomeFragment : Fragment() {
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries) val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies) val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
val livestream = dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt) val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt) val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian) val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian, livestream)
cancelBtt?.setOnClickListener { cancelBtt?.setOnClickListener {
dialog.dismissSafe() dialog.dismissSafe()

View file

@ -817,6 +817,7 @@ class CS3IPlayer : IPlayer {
// Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period // Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period
// If you can get the total time that'd be better, but this is already niche. // If you can get the total time that'd be better, but this is already niche.
&& exoPlayer?.currentTimeline?.periodCount == 1 && exoPlayer?.currentTimeline?.periodCount == 1
&& exoPlayer?.isCurrentMediaItemLive != true
} ?: false } ?: false
if (invalid) { if (invalid) {

View file

@ -364,7 +364,8 @@ class GeneratorPlayer : FullScreenPlayer() {
activity?.showDialog( activity?.showDialog(
languages.map { it.languageName }, languages.map { it.languageName },
lang639_1.indexOf(currentLanguageTwoLetters), lang639_1.indexOf(currentLanguageTwoLetters),
view?.context?.getString(R.string.subs_subtitle_languages) ?: return@setOnClickListener, view?.context?.getString(R.string.subs_subtitle_languages)
?: return@setOnClickListener,
true, true,
{ } { }
) { index -> ) { index ->
@ -721,6 +722,9 @@ class GeneratorPlayer : FullScreenPlayer() {
var maxEpisodeSet: Int? = null var maxEpisodeSet: Int? = null
override fun playerPositionChanged(posDur: Pair<Long, Long>) { override fun playerPositionChanged(posDur: Pair<Long, Long>) {
// Don't save livestream data
if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return
val (position, duration) = posDur val (position, duration) = posDur
viewModel.getId()?.let { viewModel.getId()?.let {
DataStoreHelper.setViewPos(it, position, duration) DataStoreHelper.setViewPos(it, position, duration)

View file

@ -303,6 +303,7 @@ class ResultFragment : ResultTrailerPlayer() {
TvType.Torrent -> "Torrent" TvType.Torrent -> "Torrent"
TvType.Documentary -> "Documentaries" TvType.Documentary -> "Documentaries"
TvType.AsianDrama -> "AsianDrama" TvType.AsianDrama -> "AsianDrama"
TvType.Live -> "LiveStreams"
} }
} }
@ -1665,8 +1666,13 @@ class ResultFragment : ResultTrailerPlayer() {
} }
result_resume_progress_holder?.isVisible = isProgressVisible result_resume_progress_holder?.isVisible = isProgressVisible
context?.getString(if (isProgressVisible) R.string.resume else R.string.play_movie_button) context?.getString(
?.let { when {
currentType?.isLiveStream() == true -> R.string.play_livestream_button
isProgressVisible -> R.string.resume
else -> R.string.play_movie_button
}
)?.let {
result_play_movie?.text = it result_play_movie?.text = it
} }
//println("startAction = $startAction") //println("startAction = $startAction")
@ -1943,10 +1949,10 @@ class ResultFragment : ResultTrailerPlayer() {
result_poster_holder?.visibility = VISIBLE result_poster_holder?.visibility = VISIBLE
/*result_play_movie?.text = result_play_movie?.text =
if (d.type == TvType.Torrent) getString(R.string.play_torrent_button) else getString( if (d.type == TvType.Live) getString(R.string.play_livestream_button) else getString(
R.string.play_movie_button R.string.play_movie_button
)*/ )
//result_plot_header?.text = //result_plot_header?.text =
// if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot) // if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot)
val syno = d.plot val syno = d.plot
@ -2130,6 +2136,7 @@ class ResultFragment : ResultTrailerPlayer() {
TvType.Movie -> R.string.movies_singular TvType.Movie -> R.string.movies_singular
TvType.Torrent -> R.string.torrent_singular TvType.Torrent -> R.string.torrent_singular
TvType.AsianDrama -> R.string.asian_drama_singular TvType.AsianDrama -> R.string.asian_drama_singular
TvType.Live -> R.string.live_singular
} }
)?.let { )?.let {
result_meta_type?.text = it result_meta_type?.text = it

View file

@ -498,6 +498,26 @@ class ResultViewModel : ViewModel() {
updateEpisodes(mainId, listOf(it), -1) updateEpisodes(mainId, listOf(it), -1)
} }
} }
is LiveStreamLoadResponse -> {
buildResultEpisode(
loadResponse.name,
loadResponse.name,
null,
0,
null,
loadResponse.dataUrl,
loadResponse.apiName,
(mainId), // HAS SAME ID
0,
null,
null,
null,
loadResponse.type,
mainId
).let {
updateEpisodes(mainId, listOf(it), -1)
}
}
is TorrentLoadResponse -> { is TorrentLoadResponse -> {
updateEpisodes( updateEpisodes(
mainId, listOf( mainId, listOf(

View file

@ -167,11 +167,21 @@ class SearchFragment : Fragment() {
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries) val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies) val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian) val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
val livestream =
dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt) val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt) val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
val pairList = val pairList =
HomeFragment.getPairList(anime, cartoons, tvs, docs, movies, asian) HomeFragment.getPairList(
anime,
cartoons,
tvs,
docs,
movies,
asian,
livestream
)
cancelBtt?.setOnClickListener { cancelBtt?.setOnClickListener {
dialog.dismissSafe() dialog.dismissSafe()
@ -287,6 +297,7 @@ class SearchFragment : Fragment() {
search_select_documentaries, search_select_documentaries,
search_select_movies, search_select_movies,
search_select_asian, search_select_asian,
search_select_livestreams
) )
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }

View file

@ -2,60 +2,60 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/searchRoot"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/searchRoot" android:layout_marginTop="@dimen/navbar_height"
tools:context=".ui.search.SearchFragment"
android:orientation="vertical"
android:background="?attr/primaryGrayBackground" android:background="?attr/primaryGrayBackground"
android:layout_marginTop="@dimen/navbar_height"> android:orientation="vertical"
tools:context=".ui.search.SearchFragment">
<FrameLayout <FrameLayout
android:visibility="visible" android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="10dp" android:layout_margin="10dp"
android:background="@drawable/search_background" android:background="@drawable/search_background"
android:layout_width="match_parent" android:visibility="visible">
android:layout_height="40dp">
<FrameLayout <FrameLayout
android:layout_gravity="center_vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_marginEnd="30dp" android:layout_height="30dp"
android:layout_height="30dp"> android:layout_gravity="center_vertical"
android:layout_marginEnd="30dp">
<androidx.appcompat.widget.SearchView <androidx.appcompat.widget.SearchView
android:nextFocusUp="@id/nav_rail_view"
android:nextFocusRight="@id/search_filter"
android:nextFocusLeft="@id/nav_rail_view"
android:nextFocusDown="@id/search_autofit_results"
android:imeOptions="actionSearch"
android:inputType="text"
android:id="@+id/main_search" android:id="@+id/main_search"
app:queryBackground="@color/transparent"
app:searchIcon="@drawable/search_icon"
android:paddingStart="-10dp"
android:iconifiedByDefault="false"
app:queryHint="@string/search_hint"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:iconifiedByDefault="false"
android:imeOptions="actionSearch"
android:inputType="text"
android:nextFocusLeft="@id/nav_rail_view"
android:nextFocusRight="@id/search_filter"
android:nextFocusUp="@id/nav_rail_view"
android:nextFocusDown="@id/search_autofit_results"
android:paddingStart="-10dp"
app:iconifiedByDefault="false" app:iconifiedByDefault="false"
app:queryBackground="@color/transparent"
app:queryHint="@string/search_hint"
app:searchIcon="@drawable/search_icon"
tools:ignore="RtlSymmetry"> tools:ignore="RtlSymmetry">
<requestFocus /> <requestFocus />
<androidx.core.widget.ContentLoadingProgressBar <androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/search_loading_bar" android:id="@+id/search_loading_bar"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_gravity="center"
android:layout_marginStart="-35dp" android:layout_marginStart="-35dp"
style="@style/Widget.AppCompat.ProgressBar"
android:foregroundTint="@color/white" android:foregroundTint="@color/white"
android:progressTint="@color/white" android:progressTint="@color/white">
android:layout_gravity="center">
</androidx.core.widget.ContentLoadingProgressBar> </androidx.core.widget.ContentLoadingProgressBar>
<!--app:queryHint="@string/search_hint" <!--app:queryHint="@string/search_hint"
@ -66,120 +66,126 @@
</FrameLayout> </FrameLayout>
<ImageView <ImageView
android:nextFocusUp="@id/nav_rail_view"
android:nextFocusRight="@id/main_search"
android:nextFocusLeft="@id/main_search"
android:nextFocusDown="@id/search_autofit_results"
android:id="@+id/search_filter" android:id="@+id/search_filter"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_tune_24"
android:layout_width="25dp" android:layout_width="25dp"
android:layout_height="25dp" android:layout_height="25dp"
android:layout_margin="10dp"
android:layout_gravity="end|center_vertical" android:layout_gravity="end|center_vertical"
app:tint="?attr/textColor"
android:contentDescription="@string/change_providers_img_des" /> android:layout_margin="10dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/change_providers_img_des"
android:nextFocusLeft="@id/main_search"
android:nextFocusRight="@id/main_search"
android:nextFocusUp="@id/nav_rail_view"
android:nextFocusDown="@id/search_autofit_results"
android:src="@drawable/ic_baseline_tune_24"
app:tint="?attr/textColor" />
</FrameLayout> </FrameLayout>
<HorizontalScrollView <HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fadingEdge="horizontal"
android:paddingStart="10dp" android:paddingStart="10dp"
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:fadingEdge="horizontal" android:requiresFadingEdge="horizontal">
android:requiresFadingEdge="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:nextFocusRight="@id/search_select_tv_series"
android:id="@+id/search_select_movies" android:id="@+id/search_select_movies"
android:text="@string/movies"
style="@style/RoundedSelectableButton" /> style="@style/RoundedSelectableButton"
android:nextFocusRight="@id/search_select_tv_series"
android:text="@string/movies" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/search_select_tv_series"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_movies" android:nextFocusLeft="@id/search_select_movies"
android:nextFocusRight="@id/search_select_anime" android:nextFocusRight="@id/search_select_anime"
android:text="@string/tv_series" />
android:id="@+id/search_select_tv_series"
android:text="@string/tv_series"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/search_select_anime"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_tv_series" android:nextFocusLeft="@id/search_select_tv_series"
android:nextFocusRight="@id/search_select_asian" android:nextFocusRight="@id/search_select_asian"
android:text="@string/anime" />
android:id="@+id/search_select_anime"
android:text="@string/anime"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/search_select_asian"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_anime" android:nextFocusLeft="@id/search_select_anime"
android:nextFocusRight="@id/search_select_cartoons" android:nextFocusRight="@id/search_select_cartoons"
android:text="@string/asian_drama" />
android:id="@+id/search_select_asian"
android:text="@string/asian_drama"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/search_select_cartoons"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_asian" android:nextFocusLeft="@id/search_select_asian"
android:nextFocusRight="@id/search_select_documentaries" android:nextFocusRight="@id/search_select_documentaries"
android:text="@string/cartoons" />
android:id="@+id/search_select_cartoons"
android:text="@string/cartoons"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/search_select_cartoons"
android:id="@+id/search_select_documentaries" android:id="@+id/search_select_documentaries"
android:text="@string/documentaries"
style="@style/RoundedSelectableButton" /> style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_cartoons"
android:text="@string/documentaries" />
<com.google.android.material.button.MaterialButton
android:id="@+id/search_select_livestreams"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/search_select_documentaries"
android:text="@string/livestreams" />
</LinearLayout> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>
<com.lagradost.cloudstream3.ui.AutofitRecyclerView <com.lagradost.cloudstream3.ui.AutofitRecyclerView
android:visibility="gone" android:id="@+id/search_autofit_results"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
android:background="?attr/primaryBlackBackground"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingStart="8dp"
android:paddingTop="5dp"
app:spanCount="3"
android:paddingEnd="8dp"
android:id="@+id/search_autofit_results"
tools:listitem="@layout/search_result_grid"
android:orientation="vertical" />
<androidx.recyclerview.widget.RecyclerView
android:visibility="gone"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
android:background="?attr/primaryBlackBackground" android:background="?attr/primaryBlackBackground"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:nextFocusLeft="@id/nav_rail_view"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingTop="5dp"
android:paddingEnd="8dp"
android:visibility="gone"
app:spanCount="3"
tools:listitem="@layout/search_result_grid" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_master_recycler" android:id="@+id/search_master_recycler"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/primaryBlackBackground"
android:descendantFocusability="afterDescendants"
android:nextFocusLeft="@id/nav_rail_view"
android:visibility="gone"
tools:listitem="@layout/homepage_parent" /> tools:listitem="@layout/homepage_parent" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:visibility="visible"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
android:background="?attr/primaryBlackBackground"
android:id="@+id/search_history_recycler" android:id="@+id/search_history_recycler"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/primaryBlackBackground"
android:descendantFocusability="afterDescendants"
android:nextFocusLeft="@id/nav_rail_view"
android:visibility="visible"
tools:listitem="@layout/search_history_item" /> tools:listitem="@layout/search_history_item" />
</LinearLayout> </LinearLayout>

View file

@ -1,40 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<ListView <ListView
android:clipToPadding="false"
android:nextFocusRight="@id/cancel_btt"
android:nextFocusLeft="@id/apply_btt"
android:id="@+id/listview1" android:id="@+id/listview1"
android:layout_marginBottom="60dp"
android:minHeight="0dp"
android:layout_marginTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_rowWeight="1" />
android:layout_rowWeight="1"
android:layout_marginTop="10dp"
android:layout_marginBottom="60dp"
android:clipToPadding="false"
android:minHeight="0dp"
android:nextFocusLeft="@id/apply_btt"
android:nextFocusRight="@id/cancel_btt"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice" />
<HorizontalScrollView <HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-60dp" android:layout_marginTop="-60dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:clipToPadding="true" android:clipToPadding="true"
android:fadingEdge="horizontal" android:fadingEdge="horizontal"
android:requiresFadingEdge="horizontal" android:paddingStart="10dp"
android:layout_width="wrap_content" android:paddingEnd="10dp"
android:layout_height="wrap_content"> android:requiresFadingEdge="horizontal">
<LinearLayout <LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- android:minWidth="0dp" <!-- android:minWidth="0dp"
app:iconTint="?attr/textColor" app:iconTint="?attr/textColor"
android:insetLeft="0dp" android:insetLeft="0dp"
@ -51,74 +51,81 @@
android:id="@+id/home_select_none" android:id="@+id/home_select_none"
style="@style/RoundedSelectableButtonIcon"/>--> style="@style/RoundedSelectableButtonIcon"/>-->
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:nextFocusRight="@id/home_select_tv_series"
android:id="@+id/home_select_movies" android:id="@+id/home_select_movies"
android:text="@string/movies"
style="@style/RoundedSelectableButton" /> style="@style/RoundedSelectableButton"
android:nextFocusRight="@id/home_select_tv_series"
android:text="@string/movies" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/home_select_tv_series"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_movies" android:nextFocusLeft="@id/home_select_movies"
android:nextFocusRight="@id/home_select_anime" android:nextFocusRight="@id/home_select_anime"
android:text="@string/tv_series" />
android:id="@+id/home_select_tv_series"
android:text="@string/tv_series"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/home_select_anime"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_tv_series" android:nextFocusLeft="@id/home_select_tv_series"
android:nextFocusRight="@id/home_select_asian" android:nextFocusRight="@id/home_select_asian"
android:text="@string/anime" />
android:id="@+id/home_select_anime"
android:text="@string/anime"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/home_select_asian"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_anime" android:nextFocusLeft="@id/home_select_anime"
android:nextFocusRight="@id/home_select_cartoons" android:nextFocusRight="@id/home_select_cartoons"
android:text="@string/asian_drama" />
android:id="@+id/home_select_asian"
android:text="@string/asian_drama"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/home_select_cartoons"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_asian" android:nextFocusLeft="@id/home_select_asian"
android:nextFocusRight="@id/home_select_documentaries" android:nextFocusRight="@id/home_select_documentaries"
android:text="@string/cartoons" />
android:id="@+id/home_select_cartoons"
android:text="@string/cartoons"
style="@style/RoundedSelectableButton" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/home_select_cartoons"
android:id="@+id/home_select_documentaries" android:id="@+id/home_select_documentaries"
android:text="@string/documentaries"
style="@style/RoundedSelectableButton" /> style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_cartoons"
android:text="@string/documentaries" />
<com.google.android.material.button.MaterialButton
android:id="@+id/home_select_livestreams"
style="@style/RoundedSelectableButton"
android:nextFocusLeft="@id/home_select_documentaries"
android:text="@string/livestreams" />
</LinearLayout> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>
<LinearLayout <LinearLayout
android:visibility="gone"
android:id="@+id/apply_btt_holder" android:id="@+id/apply_btt_holder"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:gravity="bottom|end" android:gravity="bottom|end"
android:layout_width="match_parent" android:orientation="horizontal"
android:layout_height="60dp"> android:visibility="gone">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
style="@style/WhiteButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_apply"
android:id="@+id/apply_btt" android:id="@+id/apply_btt"
android:layout_width="wrap_content" /> style="@style/WhiteButton"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_apply" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
style="@style/BlackButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_cancel"
android:id="@+id/cancel_btt" android:id="@+id/cancel_btt"
android:layout_width="wrap_content" /> style="@style/BlackButton"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_cancel" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -119,6 +119,7 @@
<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_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>
<string name="pick_subtitle">Subtitles</string> <string name="pick_subtitle">Subtitles</string>
@ -327,6 +328,7 @@
<string name="documentaries">Documentaries</string> <string name="documentaries">Documentaries</string>
<string name="ova">OVA</string> <string name="ova">OVA</string>
<string name="asian_drama">Asian Dramas</string> <string name="asian_drama">Asian Dramas</string>
<string name="livestreams">Livestreams</string>
<!--singular--> <!--singular-->
<string name="movies_singular">Movie</string> <string name="movies_singular">Movie</string>
@ -337,6 +339,7 @@
<string name="torrent_singular">Torrent</string> <string name="torrent_singular">Torrent</string>
<string name="documentaries_singular">Documentary</string> <string name="documentaries_singular">Documentary</string>
<string name="asian_drama_singular">Asian Drama</string> <string name="asian_drama_singular">Asian Drama</string>
<string name="live_singular">Livestream</string>
<string name="source_error">Source error</string> <string name="source_error">Source error</string>
<string name="remote_error">Remote error</string> <string name="remote_error">Remote error</string>