mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master' into exotime
This commit is contained in:
commit
4cc33146e3
17 changed files with 304 additions and 146 deletions
|
@ -1374,6 +1374,35 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
}
|
||||
|
||||
observeNullable(viewModel.favoriteStatus) observeFavoriteStatus@{ isFavorite ->
|
||||
resultviewPreviewFavorite.isVisible = isFavorite != null
|
||||
if (isFavorite == null) return@observeFavoriteStatus
|
||||
|
||||
val drawable = if (isFavorite) {
|
||||
R.drawable.ic_baseline_favorite_24
|
||||
} else {
|
||||
R.drawable.ic_baseline_favorite_border_24
|
||||
}
|
||||
|
||||
resultviewPreviewFavorite.setImageResource(drawable)
|
||||
}
|
||||
|
||||
resultviewPreviewFavorite.setOnClickListener{
|
||||
viewModel.toggleFavoriteStatus(this@MainActivity) { newStatus: Boolean? ->
|
||||
if (newStatus == null) return@toggleFavoriteStatus
|
||||
|
||||
val message = if (newStatus) {
|
||||
R.string.favorite_added
|
||||
} else {
|
||||
R.string.favorite_removed
|
||||
}
|
||||
|
||||
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||
?: txt(R.string.no_data).asStringNull(this@MainActivity) ?: ""
|
||||
showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTvSettings()) // dont want this clickable on tv layout
|
||||
resultviewPreviewDescription.setOnClickListener { view ->
|
||||
view.context?.let { ctx ->
|
||||
|
|
|
@ -18,7 +18,22 @@ open class ContentX : ExtractorApi() {
|
|||
val i_source = app.get(url, referer=ext_ref).text
|
||||
val i_extract = Regex("""window\.openPlayer\('([^']+)'""").find(i_source)!!.groups[1]?.value ?: throw ErrorLoadingException("i_extract is null")
|
||||
|
||||
val vid_source = app.get("https://contentx.me/source2.php?v=${i_extract}", referer=ext_ref).text
|
||||
val sub_urls = mutableSetOf<String>()
|
||||
Regex("""\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(i_source).forEach {
|
||||
val (sub_url, sub_lang) = it.destructured
|
||||
|
||||
if (sub_url in sub_urls) { return@forEach }
|
||||
sub_urls.add(sub_url)
|
||||
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
lang = sub_lang.replace("\\u0131", "ı").replace("\\u0130", "İ").replace("\\u00fc", "ü").replace("\\u00e7", "ç"),
|
||||
url = fixUrl(sub_url.replace("\\", ""))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val vid_source = app.get("${mainUrl}/source2.php?v=${i_extract}", referer=ext_ref).text
|
||||
val vid_extract = Regex("""file\":\"([^\"]+)""").find(vid_source)!!.groups[1]?.value ?: throw ErrorLoadingException("vid_extract is null")
|
||||
val m3u_link = vid_extract.replace("\\", "")
|
||||
|
||||
|
@ -35,7 +50,7 @@ open class ContentX : ExtractorApi() {
|
|||
|
||||
val i_dublaj = Regex(""",\"([^']+)\",\"Türkçe""").find(i_source)!!.groups[1]?.value
|
||||
if (i_dublaj != null) {
|
||||
val dublaj_source = app.get("https://contentx.me/source2.php?v=${i_dublaj}", referer=ext_ref).text
|
||||
val dublaj_source = app.get("${mainUrl}/source2.php?v=${i_dublaj}", referer=ext_ref).text
|
||||
val dublaj_extract = Regex("""file\":\"([^\"]+)""").find(dublaj_source)!!.groups[1]?.value ?: throw ErrorLoadingException("dublaj_extract is null")
|
||||
val dublaj_link = dublaj_extract.replace("\\", "")
|
||||
|
||||
|
|
|
@ -6,3 +6,8 @@ class Hotlinger : ContentX() {
|
|||
override var name = "Hotlinger"
|
||||
override var mainUrl = "https://hotlinger.com"
|
||||
}
|
||||
|
||||
class FourCX : ContentX() {
|
||||
override var name = "FourCX"
|
||||
override var mainUrl = "https://four.contentx.me"
|
||||
}
|
|
@ -9,6 +9,10 @@ class StreamTapeNet : StreamTape() {
|
|||
override var mainUrl = "https://streamtape.net"
|
||||
}
|
||||
|
||||
class StreamTapeXyz : StreamTape() {
|
||||
override var mainUrl = "https://streamtape.xyz"
|
||||
}
|
||||
|
||||
class ShaveTape : StreamTape(){
|
||||
override var mainUrl = "https://shavetape.cash"
|
||||
}
|
||||
|
|
|
@ -216,6 +216,9 @@ class HomeParentItemAdapterPreview(
|
|||
viewModel.click(callback)
|
||||
return@HomeChildItemAdapter
|
||||
}
|
||||
|
||||
(callback.view.context?.getActivity() as? MainActivity)?.loadPopup(callback.card, load = false)
|
||||
/*
|
||||
callback.view.context?.getActivity()?.showOptionSelectStringRes(
|
||||
callback.view,
|
||||
callback.card.posterUrl,
|
||||
|
@ -261,6 +264,7 @@ class HomeParentItemAdapterPreview(
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@ import android.widget.Toast
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.allViews
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.lagradost.cloudstream3.APIHolder
|
||||
|
@ -35,6 +36,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
|||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||
|
@ -80,6 +82,8 @@ data class ProviderLibraryData(
|
|||
|
||||
class LibraryFragment : Fragment() {
|
||||
companion object {
|
||||
|
||||
val listLibraryItems = mutableListOf<SyncAPI.LibraryItem>()
|
||||
fun newInstance() = LibraryFragment()
|
||||
|
||||
/**
|
||||
|
@ -91,6 +95,7 @@ class LibraryFragment : Fragment() {
|
|||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||
|
||||
var binding: FragmentLibraryBinding? = null
|
||||
private var toggleRandomButton = false
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
|
@ -196,6 +201,25 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
//Load value for toggling Random button. Hide at startup
|
||||
context?.let {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
||||
toggleRandomButton =
|
||||
settingsManager.getBoolean(
|
||||
getString(R.string.random_button_key),
|
||||
false
|
||||
) && !SettingsFragment.isTvSettings()
|
||||
binding?.libraryRandom?.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding?.libraryRandom?.setOnClickListener {
|
||||
if (listLibraryItems.isNotEmpty()) {
|
||||
val listLibraryItem = listLibraryItems.random()
|
||||
libraryViewModel.currentSyncApi?.syncIdName?.let {
|
||||
loadLibraryItem(it, listLibraryItem.syncId,listLibraryItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a plugin selection dialogue and saves the response
|
||||
|
@ -277,8 +301,10 @@ class LibraryFragment : Fragment() {
|
|||
{ isScrollingDown: Boolean ->
|
||||
if (isScrollingDown) {
|
||||
binding?.sortFab?.shrink()
|
||||
binding?.libraryRandom?.shrink()
|
||||
} else {
|
||||
binding?.sortFab?.extend()
|
||||
binding?.libraryRandom?.extend()
|
||||
}
|
||||
}) callback@{ searchClickCallback ->
|
||||
// To prevent future accidents
|
||||
|
@ -303,52 +329,7 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
|
||||
SEARCH_ACTION_LOAD -> {
|
||||
// This basically first selects the individual opener and if that is default then
|
||||
// selects the whole list opener
|
||||
val savedListSelection =
|
||||
getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncName.name)
|
||||
val savedSelection = getKey<LibraryOpener>(
|
||||
"$currentAccount/$LIBRARY_FOLDER",
|
||||
syncId
|
||||
).takeIf {
|
||||
it?.openType != LibraryOpenerType.Default
|
||||
} ?: savedListSelection
|
||||
|
||||
when (savedSelection?.openType) {
|
||||
null, LibraryOpenerType.Default -> {
|
||||
// Prevents opening MAL/AniList as a provider
|
||||
if (APIHolder.getApiFromNameNull(searchClickCallback.card.apiName) != null) {
|
||||
activity?.loadSearchResult(
|
||||
searchClickCallback.card
|
||||
)
|
||||
} else {
|
||||
// Search when no provider can open
|
||||
QuickSearchFragment.pushSearch(
|
||||
activity,
|
||||
searchClickCallback.card.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LibraryOpenerType.None -> {}
|
||||
LibraryOpenerType.Provider ->
|
||||
savedSelection.providerData?.apiName?.let { apiName ->
|
||||
activity?.loadResult(
|
||||
searchClickCallback.card.url,
|
||||
apiName,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryOpenerType.Browser ->
|
||||
openBrowser(searchClickCallback.card.url)
|
||||
|
||||
LibraryOpenerType.Search -> {
|
||||
QuickSearchFragment.pushSearch(
|
||||
activity,
|
||||
searchClickCallback.card.name
|
||||
)
|
||||
}
|
||||
}
|
||||
loadLibraryItem(syncName, syncId, searchClickCallback.card)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +395,16 @@ class LibraryFragment : Fragment() {
|
|||
binding?.viewpager?.setCurrentItem(page, false)
|
||||
}
|
||||
|
||||
observe(libraryViewModel.currentPage){
|
||||
if (toggleRandomButton) {
|
||||
listLibraryItems.clear()
|
||||
listLibraryItems.addAll(pages[it].items)
|
||||
libraryRandom.isVisible = listLibraryItems.isNotEmpty()
|
||||
} else {
|
||||
libraryRandom.isGone = true
|
||||
}
|
||||
}
|
||||
|
||||
// Only stop loading after 300ms to hide the fade effect the viewpager produces when updating
|
||||
// Without this there would be a flashing effect:
|
||||
// loading -> show old viewpager -> black screen -> show new viewpager
|
||||
|
@ -512,6 +503,62 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
})*/
|
||||
}
|
||||
|
||||
private fun loadLibraryItem(
|
||||
syncName: SyncIdName,
|
||||
syncId: String,
|
||||
card: SearchResponse
|
||||
) {
|
||||
// This basically first selects the individual opener and if that is default then
|
||||
// selects the whole list opener
|
||||
val savedListSelection =
|
||||
getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncName.name)
|
||||
|
||||
val savedSelection = getKey<LibraryOpener>(
|
||||
"$currentAccount/$LIBRARY_FOLDER",
|
||||
syncId
|
||||
).takeIf {
|
||||
it?.openType != LibraryOpenerType.Default
|
||||
} ?: savedListSelection
|
||||
|
||||
when (savedSelection?.openType) {
|
||||
null, LibraryOpenerType.Default -> {
|
||||
// Prevents opening MAL/AniList as a provider
|
||||
if (APIHolder.getApiFromNameNull(card.apiName) != null) {
|
||||
activity?.loadSearchResult(
|
||||
card
|
||||
)
|
||||
} else {
|
||||
// Search when no provider can open
|
||||
QuickSearchFragment.pushSearch(
|
||||
activity,
|
||||
card.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LibraryOpenerType.None -> {}
|
||||
LibraryOpenerType.Provider ->
|
||||
savedSelection.providerData?.apiName?.let { apiName ->
|
||||
activity?.loadResult(
|
||||
card.url,
|
||||
apiName,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryOpenerType.Browser ->
|
||||
openBrowser(card.url)
|
||||
|
||||
LibraryOpenerType.Search -> {
|
||||
QuickSearchFragment.pushSearch(
|
||||
activity,
|
||||
card.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
(binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind()
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
|
|
@ -377,7 +377,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
|||
}
|
||||
|
||||
protected fun exitFullscreen() {
|
||||
activity?.showSystemUI()
|
||||
//if (lockRotation)
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
|
||||
|
@ -389,6 +388,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
|||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|
||||
}
|
||||
activity?.window?.attributes = lp
|
||||
activity?.showSystemUI()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -1481,6 +1481,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
|||
|
||||
playerGoBack.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
activity?.showSystemUI()
|
||||
}
|
||||
|
||||
playerSourcesBtt.setOnClickListener {
|
||||
|
|
|
@ -1383,6 +1383,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
}
|
||||
|
||||
binding?.playerLoadingGoBack?.setOnClickListener {
|
||||
exitFullscreen()
|
||||
player.release()
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.ui.result
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Rect
|
||||
|
@ -31,6 +34,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||
import com.lagradost.cloudstream3.APIHolder
|
||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.DubStatus
|
||||
import com.lagradost.cloudstream3.LoadResponse
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||
|
@ -77,7 +81,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
|
||||
|
||||
open class ResultFragmentPhone : FullScreenPlayer() {
|
||||
private val gestureRegionsListener = object : PanelsChildGestureRegionObserver.GestureRegionsListener {
|
||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
||||
|
@ -247,6 +250,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
}
|
||||
|
||||
var selectSeason: String? = null
|
||||
var selectEpisodeRange: String? = null
|
||||
|
||||
private fun setUrl(url: String?) {
|
||||
if (url == null) {
|
||||
|
@ -751,6 +755,17 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
resultLoadingError.isVisible = data is Resource.Failure
|
||||
resultErrorText.isVisible = data is Resource.Failure
|
||||
resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure
|
||||
|
||||
resultTitle.setOnLongClickListener {
|
||||
val titleToCopy = resultTitle.text
|
||||
val clipboardManager =
|
||||
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?
|
||||
clipboardManager?.setPrimaryClip(ClipData.newPlainText("Title", titleToCopy))
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
showToast(R.string.copyTitle, Toast.LENGTH_SHORT)
|
||||
}
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1027,6 +1042,8 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
observeNullable(viewModel.selectedRange) { range ->
|
||||
resultBinding?.apply {
|
||||
resultEpisodeSelect.setText(range)
|
||||
|
||||
selectEpisodeRange = range?.asStringNull(resultEpisodeSelect.context)
|
||||
// If Season button is invisible then the bookmark button next focus is episode select
|
||||
if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) {
|
||||
setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect)
|
||||
|
@ -1060,9 +1077,12 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
|
||||
}
|
||||
|
||||
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->
|
||||
index to name
|
||||
}) {
|
||||
activity?.showDialog(
|
||||
names.map { it.second },
|
||||
names.indexOfFirst { it.second == selectEpisodeRange },
|
||||
"",
|
||||
false,
|
||||
{}) { itemId ->
|
||||
viewModel.changeRange(names[itemId].first)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1006,6 +1006,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
removeFavoritesData(currentId)
|
||||
statusChangedCallback?.invoke(false)
|
||||
_favoriteStatus.postValue(false)
|
||||
MainActivity.reloadLibraryEvent(true)
|
||||
} else {
|
||||
checkAndWarnDuplicates(
|
||||
context,
|
||||
|
@ -1050,8 +1051,8 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
|
||||
_favoriteStatus.postValue(true)
|
||||
|
||||
statusChangedCallback?.invoke(true)
|
||||
MainActivity.reloadLibraryEvent(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2604,6 +2605,11 @@ class ResultViewModel2 : ViewModel() {
|
|||
this.rating = searchResponse.personalRating?.times(100) ?: searchResponse.rating
|
||||
this.tags = searchResponse.tags
|
||||
}
|
||||
if (searchResponse is DataStoreHelper.BookmarkedData) {
|
||||
this.plot = searchResponse.plot
|
||||
this.rating = searchResponse.rating
|
||||
this.tags = searchResponse.tags
|
||||
}
|
||||
}
|
||||
val mainId = searchResponse.id ?: response.getId()
|
||||
|
||||
|
|
|
@ -264,6 +264,9 @@ class SearchFragment : Fragment() {
|
|||
builder.setContentView(selectMainpageBinding.root)
|
||||
builder.show()
|
||||
builder.let { dialog ->
|
||||
val previousSelectedApis = selectedApis.toSet()
|
||||
val previousSelectedSearchTypes = selectedSearchTypes.toSet()
|
||||
|
||||
val isMultiLang = ctx.getApiProviderLangSettings().let { set ->
|
||||
set.size > 1 || set.contains(AllLanguagesName)
|
||||
}
|
||||
|
@ -352,7 +355,9 @@ class SearchFragment : Fragment() {
|
|||
selectedApis = currentSelectedApis
|
||||
|
||||
// run search when dialog is close
|
||||
search(binding?.mainSearch?.query?.toString())
|
||||
if(previousSelectedApis != selectedApis.toSet() || previousSelectedSearchTypes != selectedSearchTypes.toSet()) {
|
||||
search(binding?.mainSearch?.query?.toString())
|
||||
}
|
||||
}
|
||||
updateList(selectedSearchTypes.toList())
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ import com.lagradost.cloudstream3.extractors.TauVideo
|
|||
import com.lagradost.cloudstream3.extractors.SibNet
|
||||
import com.lagradost.cloudstream3.extractors.ContentX
|
||||
import com.lagradost.cloudstream3.extractors.Hotlinger
|
||||
import com.lagradost.cloudstream3.extractors.FourCX
|
||||
import com.lagradost.cloudstream3.extractors.HDMomPlayer
|
||||
import com.lagradost.cloudstream3.extractors.HDPlayerSystem
|
||||
import com.lagradost.cloudstream3.extractors.VideoSeyred
|
||||
|
@ -151,6 +152,7 @@ import com.lagradost.cloudstream3.extractors.StreamSB8
|
|||
import com.lagradost.cloudstream3.extractors.StreamSB9
|
||||
import com.lagradost.cloudstream3.extractors.StreamTape
|
||||
import com.lagradost.cloudstream3.extractors.StreamTapeNet
|
||||
import com.lagradost.cloudstream3.extractors.StreamTapeXyz
|
||||
import com.lagradost.cloudstream3.extractors.StreamhideCom
|
||||
import com.lagradost.cloudstream3.extractors.StreamhideTo
|
||||
import com.lagradost.cloudstream3.extractors.Streamhub2
|
||||
|
@ -619,6 +621,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
|||
StreamTape(),
|
||||
StreamTapeNet(),
|
||||
ShaveTape(),
|
||||
StreamTapeXyz(),
|
||||
|
||||
//mixdrop extractors
|
||||
MixDropBz(),
|
||||
|
@ -683,6 +686,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
|||
SibNet(),
|
||||
ContentX(),
|
||||
Hotlinger(),
|
||||
FourCX(),
|
||||
HDMomPlayer(),
|
||||
HDPlayerSystem(),
|
||||
VideoSeyred(),
|
||||
|
|
|
@ -35,6 +35,7 @@ import androidx.core.graphics.blue
|
|||
import androidx.core.graphics.drawable.toBitmapOrNull
|
||||
import androidx.core.graphics.green
|
||||
import androidx.core.graphics.red
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.marginLeft
|
||||
import androidx.core.view.marginRight
|
||||
|
@ -401,81 +402,35 @@ object UIHelper {
|
|||
// Enables regular immersive mode.
|
||||
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
|
||||
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
// or View.SYSTEM_UI_FLAG_LOW_PROFILE
|
||||
)
|
||||
// window.addFlags(View.KEEP_SCREEN_ON)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
if (window.insetsController != null) {
|
||||
|
||||
window!!.insetsController?.hide(WindowInsetsCompat.Type.systemBars())
|
||||
window!!.insetsController?.systemBarsBehavior =
|
||||
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
@Suppress("DEPRECATION")
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentActivity.popCurrentPage() {
|
||||
this.onBackPressedDispatcher.onBackPressed()
|
||||
/*val currentFragment = supportFragmentManager.fragments.lastOrNull {
|
||||
it.isVisible
|
||||
} ?: return
|
||||
|
||||
supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(
|
||||
R.anim.enter_anim,
|
||||
R.anim.exit_anim,
|
||||
R.anim.pop_enter,
|
||||
R.anim.pop_exit
|
||||
)
|
||||
.remove(currentFragment)
|
||||
.commitAllowingStateLoss()*/
|
||||
}
|
||||
/*
|
||||
fun FragmentActivity.popCurrentPage(isInPlayer: Boolean, isInExpandedView: Boolean, isInResults: Boolean) {
|
||||
val currentFragment = supportFragmentManager.fragments.lastOrNull {
|
||||
it.isVisible
|
||||
}
|
||||
?: //this.onBackPressedDispatcher.onBackPressed()
|
||||
return
|
||||
|
||||
/*
|
||||
if (tvActivity == null) {
|
||||
requestedOrientation = if (settingsManager?.getBoolean("force_landscape", false) == true) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
}*/
|
||||
|
||||
// No fucked animations leaving the player :)
|
||||
when {
|
||||
isInPlayer -> {
|
||||
supportFragmentManager.beginTransaction()
|
||||
//.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit)
|
||||
.remove(currentFragment)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
isInExpandedView && !isInResults -> {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(
|
||||
R.anim.enter_anim,//R.anim.enter_from_right,
|
||||
R.anim.exit_anim,//R.anim.exit_to_right,
|
||||
R.anim.pop_enter,
|
||||
R.anim.pop_exit
|
||||
)
|
||||
.remove(currentFragment)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
else -> {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit)
|
||||
.remove(currentFragment)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fun Context.getStatusBarHeight(): Int {
|
||||
if (isTvSettings()) {
|
||||
|
@ -541,14 +496,27 @@ object UIHelper {
|
|||
}
|
||||
|
||||
fun Activity.changeStatusBarState(hide: Boolean): Int {
|
||||
@Suppress("DEPRECATION")
|
||||
return if (hide) {
|
||||
window?.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.insetsController?.hide(WindowInsets.Type.statusBars())
|
||||
|
||||
} else {
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
)
|
||||
}
|
||||
0
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.insetsController?.show(WindowInsets.Type.statusBars())
|
||||
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
}
|
||||
|
||||
this.getStatusBarHeight()
|
||||
}
|
||||
}
|
||||
|
@ -556,13 +524,20 @@ object UIHelper {
|
|||
// Shows the system bars by removing all the flags
|
||||
// except for the ones that make the content appear under the system bars.
|
||||
fun Activity.showSystemUI() {
|
||||
window.decorView.systemUiVisibility =
|
||||
|
||||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
if (window.insetsController != null) {
|
||||
window!!.insetsController?.show(WindowInsetsCompat.Type.systemBars())
|
||||
}
|
||||
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
window.decorView.systemUiVisibility =
|
||||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
}
|
||||
|
||||
changeStatusBarState(isEmulatorSettings())
|
||||
|
||||
// window.clearFlags(View.KEEP_SCREEN_ON)
|
||||
}
|
||||
|
||||
fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean {
|
||||
|
|
|
@ -41,17 +41,36 @@
|
|||
android:layout_marginStart="10dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resultview_preview_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="16sp"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
android:textStyle="bold"
|
||||
tools:text="The Perfect Run">
|
||||
<TextView
|
||||
android:id="@+id/resultview_preview_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textSize="16sp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginEnd="25dp"
|
||||
tools:text="The Perfect Run">
|
||||
|
||||
</TextView>
|
||||
</TextView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/resultview_preview_favorite"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
||||
android:layout_margin="5dp"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:elevation="10dp"
|
||||
android:nextFocusDown="@id/resultview_preview_bookmark"
|
||||
android:src="@drawable/ic_baseline_favorite_border_24"
|
||||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -123,6 +142,7 @@
|
|||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resultview_preview_bookmark"
|
||||
android:layout_weight="1"
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
android:nextFocusRight="@id/resultview_preview_more_info"
|
||||
|
||||
tools:visibility="visible"
|
||||
|
@ -136,6 +156,7 @@
|
|||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resultview_preview_more_info"
|
||||
android:layout_weight="1"
|
||||
android:nextFocusUp="@id/resultview_preview_favorite"
|
||||
android:nextFocusLeft="@id/resultview_preview_bookmark"
|
||||
|
||||
tools:visibility="visible"
|
||||
|
|
|
@ -159,6 +159,16 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="40dp">
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/library_random"
|
||||
style="@style/ExtendedFloatingActionButton"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:text="@string/home_random"
|
||||
android:textColor="?attr/textColor"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/sort_fab"
|
||||
|
|
|
@ -190,6 +190,16 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="40dp">
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/library_random"
|
||||
style="@style/ExtendedFloatingActionButton"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:text="@string/home_random"
|
||||
android:textColor="?attr/textColor"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/sort_fab"
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
<string name="sort_close">Close</string>
|
||||
<string name="sort_clear">Clear</string>
|
||||
<string name="sort_save">Save</string>
|
||||
<string name="copyTitle">Title copied!</string>
|
||||
<string name="player_speed">Player Speed</string>
|
||||
<string name="subtitles_settings">Subtitle Settings</string>
|
||||
<string name="subs_text_color">Text Color</string>
|
||||
|
@ -435,7 +436,7 @@
|
|||
<string name="pref_category_ui_features">Features</string>
|
||||
<string name="category_general">General</string>
|
||||
<string name="random_button_settings">Random Button</string>
|
||||
<string name="random_button_settings_desc">Show random button on Homepage</string>
|
||||
<string name="random_button_settings_desc">Show random button on Homepage and Library</string>
|
||||
<string name="provider_lang_settings">Provider languages</string>
|
||||
<string name="app_layout">App Layout</string>
|
||||
<string name="preferred_media_settings">Preferred media</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue