diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
index 71a24ced..63183d73 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
@@ -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 ->
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt
index 61943b70..b7f84af1 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt
@@ -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()
+ 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("\\", "")
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt
index 4a77cbf3..7389db68 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt
@@ -5,4 +5,9 @@ package com.lagradost.cloudstream3.extractors
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"
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt
index ece8dc4b..2ee98c65 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt
@@ -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"
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt
index cc4ab895..b7f601ff 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt
@@ -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(
}
}
}
+ */
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt
index a37fbcb3..8e9c8521 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt
@@ -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()
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("$currentAccount/$LIBRARY_FOLDER", syncName.name)
- val savedSelection = getKey(
- "$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("$currentAccount/$LIBRARY_FOLDER", syncName.name)
+
+ val savedSelection = getKey(
+ "$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)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
index f0622934..9dd97842 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
@@ -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 {
@@ -1575,4 +1576,4 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE // default orientation
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
index 0a626471..386e8df0 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
@@ -1383,6 +1383,7 @@ class GeneratorPlayer : FullScreenPlayer() {
}
binding?.playerLoadingGoBack?.setOnClickListener {
+ exitFullscreen()
player.release()
activity?.popCurrentPage()
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
index ad34309c..e7e50b9d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
@@ -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) {
@@ -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)
}
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
index e60c388b..c24efe56 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
@@ -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()
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt
index 7f33c08d..243d9f4e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt
@@ -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())
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
index deb0eb3c..1ae1b9b5 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
@@ -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 = arrayListOf(
StreamTape(),
StreamTapeNet(),
ShaveTape(),
+ StreamTapeXyz(),
//mixdrop extractors
MixDropBz(),
@@ -683,6 +686,7 @@ val extractorApis: MutableList = arrayListOf(
SibNet(),
ContentX(),
Hotlinger(),
+ FourCX(),
HDMomPlayer(),
HDPlayerSystem(),
VideoSeyred(),
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt
index 09ea151d..d0a2e500 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt
@@ -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 {
diff --git a/app/src/main/res/layout/bottom_resultview_preview.xml b/app/src/main/res/layout/bottom_resultview_preview.xml
index fe3f9b8d..4a64114e 100644
--- a/app/src/main/res/layout/bottom_resultview_preview.xml
+++ b/app/src/main/res/layout/bottom_resultview_preview.xml
@@ -41,17 +41,36 @@
android:layout_marginStart="10dp"
android:orientation="vertical">
-
- android:textStyle="bold"
- tools:text="The Perfect Run">
+
-
+
+
+
+
+
+
Close
Clear
Save
+ Title copied!
Player Speed
Subtitle Settings
Text Color
@@ -435,7 +436,7 @@
Features
General
Random Button
- Show random button on Homepage
+ Show random button on Homepage and Library
Provider languages
App Layout
Preferred media