weakrefrence activity for cleaner code + HomeParentItemAdapterPreview viewmodel + more stuff in viewmodel

This commit is contained in:
LagradOst 2023-07-17 03:32:41 +02:00
parent afadf121f4
commit 4d6e64adb6
29 changed files with 378 additions and 326 deletions

View File

@ -34,9 +34,18 @@ import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.UIHelper.toPx
import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.NewPipe
import java.lang.ref.WeakReference
import java.util.* import java.util.*
object CommonActivity { object CommonActivity {
private var _activity: WeakReference<Activity>? = null
var activity
get() = _activity?.get()
private set(value) {
_activity = WeakReference(value)
}
@MainThread @MainThread
fun Activity?.getCastSession(): CastSession? { fun Activity?.getCastSession(): CastSession? {
return (this as MainActivity?)?.mSessionManager?.currentCastSession return (this as MainActivity?)?.mSessionManager?.currentCastSession
@ -56,6 +65,30 @@ object CommonActivity {
var currentToast: Toast? = null var currentToast: Toast? = null
fun showToast(@StringRes message: Int, duration: Int? = null) {
val act = activity ?: return
act.runOnUiThread {
showToast(act, act.getString(message), duration)
}
}
fun showToast(message: String?, duration: Int? = null) {
val act = activity ?: return
act.runOnUiThread {
showToast(act, message, duration)
}
}
fun showToast(message: UiText?, duration: Int? = null) {
val act = activity ?: return
if (message == null) return
act.runOnUiThread {
showToast(act, message.asString(act), duration)
}
}
@MainThread
fun showToast(act: Activity?, text: UiText, duration: Int) { fun showToast(act: Activity?, text: UiText, duration: Int) {
if (act == null) return if (act == null) return
text.asStringNull(act)?.let { text.asStringNull(act)?.let {
@ -140,6 +173,7 @@ object CommonActivity {
fun init(act: ComponentActivity?) { fun init(act: ComponentActivity?) {
if (act == null) return if (act == null) return
activity = act
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission //https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
//https://developer.android.com/guide/topics/ui/picture-in-picture //https://developer.android.com/guide/topics/ui/picture-in-picture
canShowPipMode = canShowPipMode =
@ -222,6 +256,7 @@ object CommonActivity {
"AmoledLight" -> R.style.AmoledModeLight "AmoledLight" -> R.style.AmoledModeLight
"Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.MonetMode else R.style.AppTheme R.style.MonetMode else R.style.AppTheme
else -> R.style.AppTheme else -> R.style.AppTheme
} }
@ -244,8 +279,10 @@ object CommonActivity {
"Pink" -> R.style.OverlayPrimaryColorPink "Pink" -> R.style.OverlayPrimaryColorPink
"Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "Monet" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.OverlayPrimaryColorMonet else R.style.OverlayPrimaryColorNormal R.style.OverlayPrimaryColorMonet else R.style.OverlayPrimaryColorNormal
"Monet2" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "Monet2" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
R.style.OverlayPrimaryColorMonetTwo else R.style.OverlayPrimaryColorNormal R.style.OverlayPrimaryColorMonetTwo else R.style.OverlayPrimaryColorNormal
else -> R.style.OverlayPrimaryColorNormal else -> R.style.OverlayPrimaryColorNormal
} }
act.theme.applyStyle(currentTheme, true) act.theme.applyStyle(currentTheme, true)
@ -271,12 +308,15 @@ object CommonActivity {
FocusDirection.Left -> { FocusDirection.Left -> {
view.nextFocusLeftId view.nextFocusLeftId
} }
FocusDirection.Up -> { FocusDirection.Up -> {
view.nextFocusUpId view.nextFocusUpId
} }
FocusDirection.Right -> { FocusDirection.Right -> {
view.nextFocusRightId view.nextFocusRightId
} }
FocusDirection.Down -> { FocusDirection.Down -> {
view.nextFocusDownId view.nextFocusDownId
} }
@ -328,30 +368,39 @@ object CommonActivity {
KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> { KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {
PlayerEventType.SeekForward PlayerEventType.SeekForward
} }
KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> { KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
PlayerEventType.SeekBack PlayerEventType.SeekBack
} }
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1, KeyEvent.KEYCODE_N -> { KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1, KeyEvent.KEYCODE_N -> {
PlayerEventType.NextEpisode PlayerEventType.NextEpisode
} }
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_B -> { KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_B -> {
PlayerEventType.PrevEpisode PlayerEventType.PrevEpisode
} }
KeyEvent.KEYCODE_MEDIA_PAUSE -> { KeyEvent.KEYCODE_MEDIA_PAUSE -> {
PlayerEventType.Pause PlayerEventType.Pause
} }
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> { KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> {
PlayerEventType.Play PlayerEventType.Play
} }
KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7, KeyEvent.KEYCODE_7 -> { KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7, KeyEvent.KEYCODE_7 -> {
PlayerEventType.Lock PlayerEventType.Lock
} }
KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> { KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> {
PlayerEventType.ToggleHide PlayerEventType.ToggleHide
} }
KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> { KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> {
PlayerEventType.ToggleMute PlayerEventType.ToggleMute
} }
KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9, KeyEvent.KEYCODE_9 -> { KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9, KeyEvent.KEYCODE_9 -> {
PlayerEventType.ShowMirrors PlayerEventType.ShowMirrors
} }
@ -359,21 +408,27 @@ object CommonActivity {
KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_NUMPAD_8, KeyEvent.KEYCODE_8 -> { KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_NUMPAD_8, KeyEvent.KEYCODE_8 -> {
PlayerEventType.SearchSubtitlesOnline PlayerEventType.SearchSubtitlesOnline
} }
KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3, KeyEvent.KEYCODE_3 -> { KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3, KeyEvent.KEYCODE_3 -> {
PlayerEventType.ShowSpeed PlayerEventType.ShowSpeed
} }
KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0, KeyEvent.KEYCODE_0 -> { KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0, KeyEvent.KEYCODE_0 -> {
PlayerEventType.Resize PlayerEventType.Resize
} }
KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4, KeyEvent.KEYCODE_4 -> { KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4, KeyEvent.KEYCODE_4 -> {
PlayerEventType.SkipOp PlayerEventType.SkipOp
} }
KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_NUMPAD_5, KeyEvent.KEYCODE_5 -> { KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_NUMPAD_5, KeyEvent.KEYCODE_5 -> {
PlayerEventType.SkipCurrentChapter PlayerEventType.SkipCurrentChapter
} }
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation
PlayerEventType.PlayPauseToggle PlayerEventType.PlayPauseToggle
} }
else -> null else -> null
}?.let { playerEvent -> }?.let { playerEvent ->
playerEventListener?.invoke(playerEvent) playerEventListener?.invoke(playerEvent)
@ -398,16 +453,19 @@ object CommonActivity {
act.currentFocus, act.currentFocus,
FocusDirection.Left FocusDirection.Left
) )
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus( KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
act, act,
act.currentFocus, act.currentFocus,
FocusDirection.Right FocusDirection.Right
) )
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus( KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
act, act,
act.currentFocus, act.currentFocus,
FocusDirection.Up FocusDirection.Up
) )
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus( KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
act, act,
act.currentFocus, act.currentFocus,

View File

@ -309,7 +309,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
this@with.runOnUiThread { this@with.runOnUiThread {
try { try {
showToast( showToast(
this@with,
getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail).format( getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail).format(
api.name api.name
) )
@ -785,7 +784,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
newLocalBinding newLocalBinding
} }
} catch (t: Throwable) { } catch (t: Throwable) {
showToast(this, txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG) showToast(txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG)
null null
} }
@ -817,7 +816,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
if (PluginManager.checkSafeModeFile()) { if (PluginManager.checkSafeModeFile()) {
normalSafeApiCall { normalSafeApiCall {
showToast(this, R.string.safe_mode_file, Toast.LENGTH_LONG) showToast( R.string.safe_mode_file, Toast.LENGTH_LONG)
} }
} else if (lastError == null) { } else if (lastError == null) {
ioSafe { ioSafe {
@ -876,7 +875,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} }
when (resource) { when (resource) {
is Resource.Failure -> { is Resource.Failure -> {
showToast(this, R.string.error) showToast(R.string.error)
viewModel.clear() viewModel.clear()
hidePreviewPopupDialog() hidePreviewPopupDialog()
} }

View File

@ -5,6 +5,7 @@ import android.content.DialogInterface
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -19,7 +20,7 @@ import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager import com.lagradost.cloudstream3.utils.VideoDownloadManager
object DownloadButtonSetup { object DownloadButtonSetup {
fun handleDownloadClick(activity: Activity?, click: DownloadClickEvent) { fun handleDownloadClick(click: DownloadClickEvent) {
val id = click.data.id val id = click.data.id
if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return
when (click.action) { when (click.action) {
@ -89,9 +90,9 @@ object DownloadButtonSetup {
)?.fileLength )?.fileLength
?: 0 ?: 0
if (length > 0) { if (length > 0) {
showToast(act, R.string.delete, Toast.LENGTH_LONG) showToast(R.string.delete, Toast.LENGTH_LONG)
} else { } else {
showToast(act, R.string.download, Toast.LENGTH_LONG) showToast(R.string.download, Toast.LENGTH_LONG)
} }
} }
} }

View File

@ -95,7 +95,7 @@ class DownloadChildFragment : Fragment() {
DownloadChildAdapter( DownloadChildAdapter(
ArrayList(), ArrayList(),
) { click -> ) { click ->
handleDownloadClick(activity, click) handleDownloadClick(click)
} }
downloadDeleteEventListener = { id: Int -> downloadDeleteEventListener = { id: Int ->

View File

@ -162,7 +162,7 @@ class DownloadFragment : Fragment() {
}, },
{ downloadClickEvent -> { downloadClickEvent ->
if (downloadClickEvent.data !is VideoDownloadHelper.DownloadEpisodeCached) return@DownloadHeaderAdapter if (downloadClickEvent.data !is VideoDownloadHelper.DownloadEpisodeCached) return@DownloadHeaderAdapter
handleDownloadClick(activity, downloadClickEvent) handleDownloadClick(downloadClickEvent)
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) { if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
context?.let { ctx -> context?.let { ctx ->
downloadsViewModel.updateList(ctx) downloadsViewModel.updateList(ctx)
@ -230,7 +230,7 @@ class DownloadFragment : Fragment() {
binding.applyBtt.setOnClickListener { binding.applyBtt.setOnClickListener {
val url = binding.streamUrl.text?.toString() val url = binding.streamUrl.text?.toString()
if (url.isNullOrEmpty()) { if (url.isNullOrEmpty()) {
showToast(activity, R.string.error_invalid_url, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT)
} else { } else {
val referer = binding.streamReferer.text?.toString() val referer = binding.streamReferer.text?.toString()

View File

@ -42,6 +42,7 @@ import com.lagradost.cloudstream3.databinding.TvtypesChipsBinding
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.mvvm.observeNullable
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
@ -194,7 +195,7 @@ class HomeFragment : Fragment() {
binding.homeExpandedRecycler.adapter = binding.homeExpandedRecycler.adapter =
SearchAdapter(item.list.toMutableList(), binding.homeExpandedRecycler) { callback -> SearchAdapter(item.list.toMutableList(), binding.homeExpandedRecycler) { callback ->
handleSearchClickCallback(this, callback) handleSearchClickCallback(callback)
if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) { if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {
bottomSheetDialogBuilder.ownHide() // we hide here because we want to resume it later bottomSheetDialogBuilder.ownHide() // we hide here because we want to resume it later
//bottomSheetDialogBuilder.dismissSafe(this) //bottomSheetDialogBuilder.dismissSafe(this)
@ -440,8 +441,8 @@ class HomeFragment : Fragment() {
val root = inflater.inflate(layout, container, false) val root = inflater.inflate(layout, container, false)
binding = try { binding = try {
FragmentHomeBinding.bind(root) FragmentHomeBinding.bind(root)
} catch (t : Throwable) { } catch (t: Throwable) {
showToast(activity, txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG) showToast(txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG)
logError(t) logError(t)
null null
} }
@ -481,59 +482,6 @@ class HomeFragment : Fragment() {
fixGrid() fixGrid()
} }
fun bookmarksUpdated(_data: Boolean) {
reloadStored()
}
override fun onResume() {
super.onResume()
reloadStored()
bookmarksUpdatedEvent += ::bookmarksUpdated
afterPluginsLoadedEvent += ::afterPluginsLoaded
mainPluginsLoadedEvent += ::afterMainPluginsLoaded
}
override fun onStop() {
bookmarksUpdatedEvent -= ::bookmarksUpdated
afterPluginsLoadedEvent -= ::afterPluginsLoaded
mainPluginsLoadedEvent -= ::afterMainPluginsLoaded
super.onStop()
}
private fun reloadStored() {
homeViewModel.loadResumeWatching()
val list = EnumSet.noneOf(WatchType::class.java)
getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
list.addAll(it)
}
homeViewModel.loadStoredData(list)
}
private fun afterMainPluginsLoaded(unused: Boolean = false) {
loadHomePage(false)
}
private fun afterPluginsLoaded(forceReload: Boolean) {
loadHomePage(forceReload)
}
private fun loadHomePage(forceReload: Boolean) {
val apiName = context?.getKey<String>(USER_SELECTED_HOMEPAGE_API)
if (homeViewModel.apiName.value != apiName || apiName == null || forceReload) {
//println("Caught home: " + homeViewModel.apiName.value + " at " + apiName)
homeViewModel.loadAndCancel(apiName, forceReload)
}
}
private fun homeHandleSearch(callback: SearchClickCallback) {
if (callback.action == SEARCH_ACTION_FOCUSED) {
//focusCallback(callback.card)
} else {
handleSearchClickCallback(activity, callback)
}
}
private var currentApiName: String? = null private var currentApiName: String? = null
private var toggleRandomButton = false private var toggleRandomButton = false
@ -546,8 +494,6 @@ class HomeFragment : Fragment() {
fixGrid() fixGrid()
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener) binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener) binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
binding?.homeApiFab?.setOnClickListener(apiChangeClickListener) binding?.homeApiFab?.setOnClickListener(apiChangeClickListener)
binding?.homeRandom?.setOnClickListener { binding?.homeRandom?.setOnClickListener {
@ -567,18 +513,9 @@ class HomeFragment : Fragment() {
binding?.homeRandom?.visibility = View.GONE binding?.homeRandom?.visibility = View.GONE
} }
observe(homeViewModel.preview) { preview ->
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setPreviewData(
preview
)
}
observe(homeViewModel.apiName) { apiName -> observe(homeViewModel.apiName) { apiName ->
currentApiName = apiName currentApiName = apiName
binding?.homeApiFab?.text = apiName binding?.homeApiFab?.text = apiName
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setApiName(
apiName
)
} }
observe(homeViewModel.page) { data -> observe(homeViewModel.page) { data ->
@ -659,73 +596,38 @@ class HomeFragment : Fragment() {
} }
observe(homeViewModel.availableWatchStatusTypes) { availableWatchStatusTypes ->
context?.setKey(
HOME_BOOKMARK_VALUE_LIST,
availableWatchStatusTypes.first.map { it.internalId }.toIntArray()
)
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setAvailableWatchStatusTypes(
availableWatchStatusTypes
)
}
observe(homeViewModel.bookmarks) { data ->
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setBookmarkData(
data
)
}
observe(homeViewModel.resumeWatching) { resumeWatching ->
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setResumeWatchingData(
resumeWatching
)
if (isTrueTvSettings()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ioSafe {
activity?.addProgramsToContinueWatching(resumeWatching.mapNotNull { it as? DataStoreHelper.ResumeWatchingResult })
}
}
}
}
//context?.fixPaddingStatusbarView(home_statusbar) //context?.fixPaddingStatusbarView(home_statusbar)
//context?.fixPaddingStatusbar(home_padding) //context?.fixPaddingStatusbar(home_padding)
fixPaddingStatusbar(binding?.homeLoadingStatusbar) fixPaddingStatusbar(binding?.homeLoadingStatusbar)
binding?.homeMasterRecycler?.adapter = observeNullable(homeViewModel.popup) { item ->
HomeParentItemAdapterPreview(mutableListOf(), { callback -> if (item == null) {
homeHandleSearch(callback) bottomSheetDialog?.dismissSafe()
}, { item -> bottomSheetDialog = null
bottomSheetDialog = activity?.loadHomepageList(item, expandCallback = { return@observeNullable
homeViewModel.expandAndReturn(it) }
}, dismissCallback = {
bottomSheetDialog = null
})
}, { name ->
homeViewModel.expand(name)
}, { load ->
activity?.loadResult(load.response.url, load.response.apiName, load.action)
}, {
homeViewModel.loadMoreHomeScrollResponses()
}, {
apiChangeClickListener.onClick(it)
}, reloadStored = {
reloadStored()
}, loadStoredData = {
homeViewModel.loadStoredData(it)
}, { (isQuickSearch, text) ->
if (!isQuickSearch) {
QuickSearchFragment.pushSearch(
activity,
text,
currentApiName?.let { arrayOf(it) })
}
})
reloadStored() // don't recreate
loadHomePage(false) if (bottomSheetDialog != null) {
return@observeNullable
}
bottomSheetDialog = activity?.loadHomepageList(item, expandCallback = {
homeViewModel.expandAndReturn(it)
}, dismissCallback = {
homeViewModel.popup(null)
bottomSheetDialog = null
})
}
binding?.homeMasterRecycler?.adapter =
HomeParentItemAdapterPreview(
mutableListOf(),
homeViewModel
)
homeViewModel.reloadStored()
//loadHomePage(false)
binding?.homeMasterRecycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding?.homeMasterRecycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {

View File

@ -26,6 +26,7 @@ class LoadClickCallback(
open class ParentItemAdapter( open class ParentItemAdapter(
private var items: MutableList<HomeViewModel.ExpandableHomepageList>, private var items: MutableList<HomeViewModel.ExpandableHomepageList>,
//private val viewModel: HomeViewModel,
private val clickCallback: (SearchClickCallback) -> Unit, private val clickCallback: (SearchClickCallback) -> Unit,
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit, private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
private val expandCallback: ((String) -> Unit)? = null, private val expandCallback: ((String) -> Unit)? = null,
@ -153,6 +154,7 @@ open class ParentItemAdapter(
class ParentViewHolder class ParentViewHolder
constructor( constructor(
val binding: HomepageParentBinding, val binding: HomepageParentBinding,
// val viewModel: HomeViewModel,
private val clickCallback: (SearchClickCallback) -> Unit, private val clickCallback: (SearchClickCallback) -> Unit,
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit, private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
private val expandCallback: ((String) -> Unit)? = null, private val expandCallback: ((String) -> Unit)? = null,

View File

@ -8,7 +8,9 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable import com.google.android.material.chip.ChipDrawable
@ -18,8 +20,13 @@ import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.databinding.FragmentHomeHeadBinding
import com.lagradost.cloudstream3.databinding.FragmentHomeHeadTvBinding
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.debugException
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.selectHomepage
import com.lagradost.cloudstream3.ui.result.ResultViewModel2 import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
@ -61,102 +68,51 @@ import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_type_on_ho
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_type_watching_btt import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_type_watching_btt
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_watch_child_recyclerview import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_watch_child_recyclerview
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_watch_holder import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_watch_holder
import kotlinx.android.synthetic.main.toast.view.*
class HomeParentItemAdapterPreview( class HomeParentItemAdapterPreview(
items: MutableList<HomeViewModel.ExpandableHomepageList>, items: MutableList<HomeViewModel.ExpandableHomepageList>,
val clickCallback: (SearchClickCallback) -> Unit, private val viewModel: HomeViewModel,
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit, ) : ParentItemAdapter(items, clickCallback = {
expandCallback: ((String) -> Unit)? = null, viewModel.click(it)
private val loadCallback: (LoadClickCallback) -> Unit, }, moreInfoClickCallback = {
private val loadMoreCallback: (() -> Unit), viewModel.popup(it)
private val changeHomePageCallback: ((View) -> Unit), }, expandCallback = {
private val reloadStored: (() -> Unit), viewModel.expand(it)
private val loadStoredData: ((Set<WatchType>) -> Unit), }) {
private val searchQueryCallback: ((Pair<Boolean, String>) -> Unit)
) : ParentItemAdapter(items, clickCallback, moreInfoClickCallback, expandCallback) {
private var previewData: Resource<Pair<Boolean, List<LoadResponse>>> = Resource.Loading()
private var resumeWatchingData: List<SearchResponse> = listOf()
private var bookmarkData: Pair<Boolean, List<SearchResponse>> =
false to listOf()
private var apiName: String = "NONE"
val headItems = 1 val headItems = 1
private var availableWatchStatusTypes: Pair<Set<WatchType>, Set<WatchType>> =
setOf<WatchType>() to setOf()
fun setAvailableWatchStatusTypes(data: Pair<Set<WatchType>, Set<WatchType>>) {
availableWatchStatusTypes = data
holder?.setAvailableWatchStatusTypes(data)
}
companion object { companion object {
private const val VIEW_TYPE_HEADER = 2 private const val VIEW_TYPE_HEADER = 2
private const val VIEW_TYPE_ITEM = 1 private const val VIEW_TYPE_ITEM = 1
} }
fun setResumeWatchingData(resumeWatching: List<SearchResponse>) {
resumeWatchingData = resumeWatching
holder?.updateResume(resumeWatchingData)
}
fun setPreviewData(preview: Resource<Pair<Boolean, List<LoadResponse>>>) {
previewData = preview
holder?.updatePreview(preview)
}
fun setApiName(name: String) {
apiName = name
holder?.updateApiName(name)
}
fun setBookmarkData(data: Pair<Boolean, List<SearchResponse>>) {
bookmarkData = data
holder?.updateBookmarks(data)
}
override fun getItemViewType(position: Int) = when (position) { override fun getItemViewType(position: Int) = when (position) {
0 -> VIEW_TYPE_HEADER 0 -> VIEW_TYPE_HEADER
else -> VIEW_TYPE_ITEM else -> VIEW_TYPE_ITEM
} }
var holder: HeaderViewHolder? = null
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) { when (holder) {
is HeaderViewHolder -> { is HeaderViewHolder -> {}
holder.updatePreview(previewData) else -> super.onBindViewHolder(holder, position - headItems)
holder.updateResume(resumeWatchingData)
holder.updateBookmarks(bookmarkData)
holder.setAvailableWatchStatusTypes(availableWatchStatusTypes)
holder.updateApiName(apiName)
}
else -> super.onBindViewHolder(holder, position - 1)
} }
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
println("onCreateViewHolder $viewType")
return when (viewType) { return when (viewType) {
VIEW_TYPE_HEADER -> HeaderViewHolder( VIEW_TYPE_HEADER -> {
LayoutInflater.from(parent.context).inflate( val inflater = LayoutInflater.from(parent.context)
if (isTvSettings()) R.layout.fragment_home_head_tv else R.layout.fragment_home_head, val binding = if (isTvSettings()) FragmentHomeHeadTvBinding.inflate(
inflater,
parent, parent,
false false
), ) else FragmentHomeHeadBinding.inflate(inflater, parent, false)
loadCallback, HeaderViewHolder(
loadMoreCallback, binding,
changeHomePageCallback, viewModel,
clickCallback, )
reloadStored,
loadStoredData,
searchQueryCallback,
moreInfoClickCallback
).also {
this.holder = it
} }
VIEW_TYPE_ITEM -> super.onCreateViewHolder(parent, viewType) VIEW_TYPE_ITEM -> super.onCreateViewHolder(parent, viewType)
else -> error("Unhandled viewType=$viewType") else -> error("Unhandled viewType=$viewType")
} }
@ -167,7 +123,7 @@ class HomeParentItemAdapterPreview(
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
if (position == 0) return previewData.hashCode().toLong() if (position == 0) return 0//previewData.hashCode().toLong()
return super.getItemId(position - headItems) return super.getItemId(position - headItems)
} }
@ -176,6 +132,7 @@ class HomeParentItemAdapterPreview(
is HeaderViewHolder -> { is HeaderViewHolder -> {
holder.onViewDetachedFromWindow() holder.onViewDetachedFromWindow()
} }
else -> super.onViewDetachedFromWindow(holder) else -> super.onViewDetachedFromWindow(holder)
} }
} }
@ -185,6 +142,7 @@ class HomeParentItemAdapterPreview(
is HeaderViewHolder -> { is HeaderViewHolder -> {
holder.onViewAttachedToWindow() holder.onViewAttachedToWindow()
} }
else -> super.onViewAttachedToWindow(holder) else -> super.onViewAttachedToWindow(holder)
} }
} }
@ -192,16 +150,9 @@ class HomeParentItemAdapterPreview(
class HeaderViewHolder class HeaderViewHolder
constructor( constructor(
itemView: View, val binding: ViewBinding,
private val clickCallback: ((LoadClickCallback) -> Unit)?, val viewModel: HomeViewModel,
private val loadMoreCallback: (() -> Unit), ) : RecyclerView.ViewHolder(binding.root) {
private val changeHomePageCallback: ((View) -> Unit),
private val searchClickCallback: (SearchClickCallback) -> Unit,
private val reloadStored: () -> Unit,
private val loadStoredData: ((Set<WatchType>) -> Unit),
private val searchQueryCallback: ((Pair<Boolean, String>) -> Unit),
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit
) : RecyclerView.ViewHolder(itemView) {
private var previewAdapter: HomeScrollAdapter? = null private var previewAdapter: HomeScrollAdapter? = null
private val previewViewpager: ViewPager2? = itemView.home_preview_viewpager private val previewViewpager: ViewPager2? = itemView.home_preview_viewpager
private val previewHeader: FrameLayout? = itemView.home_preview private val previewHeader: FrameLayout? = itemView.home_preview
@ -214,8 +165,8 @@ class HomeParentItemAdapterPreview(
previewAdapter?.apply { previewAdapter?.apply {
if (position >= itemCount - 1 && hasMoreItems) { if (position >= itemCount - 1 && hasMoreItems) {
hasMoreItems = false // dont make two requests hasMoreItems = false // don't make two requests
loadMoreCallback() viewModel.loadMoreHomeScrollResponses()
//homeViewModel.loadMoreHomeScrollResponses() //homeViewModel.loadMoreHomeScrollResponses()
} }
} }
@ -261,7 +212,7 @@ class HomeParentItemAdapterPreview(
// itemView.home_preview_title?.text = name // itemView.home_preview_title?.text = name
itemView.home_preview_play?.setOnClickListener { view -> itemView.home_preview_play?.setOnClickListener { view ->
clickCallback?.invoke( viewModel.click(
LoadClickCallback( LoadClickCallback(
START_ACTION_RESUME_LATEST, START_ACTION_RESUME_LATEST,
view, view,
@ -271,13 +222,13 @@ class HomeParentItemAdapterPreview(
) )
} }
itemView.home_preview_info?.setOnClickListener { view -> itemView.home_preview_info?.setOnClickListener { view ->
clickCallback?.invoke( viewModel.click(
LoadClickCallback(0, view, position, this) LoadClickCallback(0, view, position, this)
) )
} }
itemView.home_preview_play_btt?.setOnClickListener { view -> itemView.home_preview_play_btt?.setOnClickListener { view ->
clickCallback?.invoke( viewModel.click(
LoadClickCallback( LoadClickCallback(
START_ACTION_RESUME_LATEST, START_ACTION_RESUME_LATEST,
view, view,
@ -298,7 +249,7 @@ class HomeParentItemAdapterPreview(
itemView.home_preview_info_btt?.setOnClickListener { view -> itemView.home_preview_info_btt?.setOnClickListener { view ->
clickCallback?.invoke( viewModel.click(
LoadClickCallback(0, view, position, this) LoadClickCallback(0, view, position, this)
) )
} }
@ -362,7 +313,7 @@ class HomeParentItemAdapterPreview(
this, this,
newValue newValue
) )
reloadStored() viewModel.reloadStored()
} }
} }
} }
@ -384,6 +335,24 @@ class HomeParentItemAdapterPreview(
fun onViewAttachedToWindow() { fun onViewAttachedToWindow() {
previewViewpager?.registerOnPageChangeCallback(previewCallback) previewViewpager?.registerOnPageChangeCallback(previewCallback)
binding.root.findViewTreeLifecycleOwner()?.apply {
observe(viewModel.preview) {
updatePreview(it)
}
observe(viewModel.apiName) {
updateApiName(it)
}
observe(viewModel.resumeWatching) {
updateResume(it)
}
observe(viewModel.bookmarks) {
updateBookmarks(it)
}
observe(viewModel.availableWatchStatusTypes) {
setAvailableWatchStatusTypes(it)
}
} ?: debugException { "Expected findViewTreeLifecycleOwner" }
} }
private val toggleList = listOf( private val toggleList = listOf(
@ -395,11 +364,17 @@ class HomeParentItemAdapterPreview(
) )
init { init {
itemView.home_preview_change_api?.setOnClickListener { view -> if (binding is FragmentHomeHeadTvBinding) {
changeHomePageCallback(view) binding.homePreviewChangeApi.setOnClickListener { view ->
} view.context.selectHomepage(viewModel.repo?.name) { api ->
itemView.home_preview_change_api2?.setOnClickListener { view -> viewModel.loadAndCancel(api)
changeHomePageCallback(view) }
}
binding.homePreviewChangeApi2.setOnClickListener { view ->
view.context.selectHomepage(viewModel.repo?.name) { api ->
viewModel.loadAndCancel(api)
}
}
} }
previewViewpager?.apply { previewViewpager?.apply {
@ -421,7 +396,7 @@ class HomeParentItemAdapterPreview(
nextFocusDown = itemView.nextFocusDownId nextFocusDown = itemView.nextFocusDownId
) { callback -> ) { callback ->
if (callback.action != SEARCH_ACTION_SHOW_METADATA) { if (callback.action != SEARCH_ACTION_SHOW_METADATA) {
searchClickCallback(callback) viewModel.click(callback)
return@HomeChildItemAdapter return@HomeChildItemAdapter
} }
callback.view.context?.getActivity()?.showOptionSelectStringRes( callback.view.context?.getActivity()?.showOptionSelectStringRes(
@ -440,7 +415,7 @@ class HomeParentItemAdapterPreview(
when (actionId + if (isTv) 0 else 1) { when (actionId + if (isTv) 0 else 1) {
// play // play
0 -> { 0 -> {
searchClickCallback.invoke( viewModel.click(
SearchClickCallback( SearchClickCallback(
START_ACTION_RESUME_LATEST, START_ACTION_RESUME_LATEST,
callback.view, callback.view,
@ -448,11 +423,11 @@ class HomeParentItemAdapterPreview(
callback.card callback.card
) )
) )
reloadStored() viewModel.reloadStored()
} }
//info //info
1 -> { 1 -> {
searchClickCallback( viewModel.click(
SearchClickCallback( SearchClickCallback(
SEARCH_ACTION_LOAD, SEARCH_ACTION_LOAD,
callback.view, callback.view,
@ -461,14 +436,14 @@ class HomeParentItemAdapterPreview(
) )
) )
reloadStored() viewModel.reloadStored()
} }
// remove // remove
2 -> { 2 -> {
val card = callback.card val card = callback.card
if (card is DataStoreHelper.ResumeWatchingResult) { if (card is DataStoreHelper.ResumeWatchingResult) {
DataStoreHelper.removeLastWatched(card.parentId) DataStoreHelper.removeLastWatched(card.parentId)
reloadStored() viewModel.reloadStored()
} }
} }
} }
@ -483,7 +458,7 @@ class HomeParentItemAdapterPreview(
nextFocusDown = itemView.nextFocusDownId nextFocusDown = itemView.nextFocusDownId
) { callback -> ) { callback ->
if (callback.action != SEARCH_ACTION_SHOW_METADATA) { if (callback.action != SEARCH_ACTION_SHOW_METADATA) {
searchClickCallback(callback) viewModel.click(callback)
return@HomeChildItemAdapter return@HomeChildItemAdapter
} }
callback.view.context?.getActivity()?.showOptionSelectStringRes( callback.view.context?.getActivity()?.showOptionSelectStringRes(
@ -501,7 +476,7 @@ class HomeParentItemAdapterPreview(
) { (isTv, actionId) -> ) { (isTv, actionId) ->
when (actionId + if (isTv) 0 else 1) { // play when (actionId + if (isTv) 0 else 1) { // play
0 -> { 0 -> {
searchClickCallback.invoke( viewModel.click(
SearchClickCallback( SearchClickCallback(
START_ACTION_RESUME_LATEST, START_ACTION_RESUME_LATEST,
callback.view, callback.view,
@ -509,10 +484,11 @@ class HomeParentItemAdapterPreview(
callback.card callback.card
) )
) )
reloadStored() viewModel.reloadStored()
} }
1 -> { // info 1 -> { // info
searchClickCallback( viewModel.click(
SearchClickCallback( SearchClickCallback(
SEARCH_ACTION_LOAD, SEARCH_ACTION_LOAD,
callback.view, callback.view,
@ -521,14 +497,15 @@ class HomeParentItemAdapterPreview(
) )
) )
reloadStored() viewModel.reloadStored()
} }
2 -> { // remove 2 -> { // remove
DataStoreHelper.setResultWatchState( DataStoreHelper.setResultWatchState(
callback.card.id, callback.card.id,
WatchType.NONE.internalId WatchType.NONE.internalId
) )
reloadStored() viewModel.reloadStored()
} }
} }
} }
@ -540,7 +517,7 @@ class HomeParentItemAdapterPreview(
chip?.isChecked = false chip?.isChecked = false
chip?.setOnCheckedChangeListener { _, isChecked -> chip?.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) { if (isChecked) {
loadStoredData( viewModel.loadStoredData(
setOf(watch) setOf(watch)
// If we filter all buttons then two can be checked at the same time // If we filter all buttons then two can be checked at the same time
// Revert this if you want to go back to multi selection // Revert this if you want to go back to multi selection
@ -549,7 +526,7 @@ class HomeParentItemAdapterPreview(
} }
// Else if all are unchecked -> Do not load data // Else if all are unchecked -> Do not load data
else if (toggleList.all { it.first?.isChecked != true }) { else if (toggleList.all { it.first?.isChecked != true }) {
loadStoredData(emptySet()) viewModel.loadStoredData(emptySet())
} }
} }
} }
@ -558,25 +535,26 @@ class HomeParentItemAdapterPreview(
itemView.home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { itemView.home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
searchQueryCallback.invoke(false to query) viewModel.queryTextSubmit(query)
//QuickSearchFragment.pushSearch(activity, query, currentApiName?.let { arrayOf(it) } //QuickSearchFragment.pushSearch(activity, query, currentApiName?.let { arrayOf(it) }
return true return true
} }
override fun onQueryTextChange(newText: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
searchQueryCallback.invoke(true to newText) viewModel.queryTextChange(newText)
//searchViewModel.quickSearch(newText) //searchViewModel.quickSearch(newText)
return true return true
} }
}) })
} }
fun updateApiName(name: String) { private fun updateApiName(name: String) {
itemView.home_preview_change_api2?.text = name itemView.home_preview_change_api2?.text = name
itemView.home_preview_change_api?.text = name itemView.home_preview_change_api?.text = name
} }
fun updatePreview(preview: Resource<Pair<Boolean, List<LoadResponse>>>) { private fun updatePreview(preview: Resource<Pair<Boolean, List<LoadResponse>>>) {
itemView.home_preview_change_api2?.isGone = preview is Resource.Success itemView.home_preview_change_api2?.isGone = preview is Resource.Success
if (preview is Resource.Success) { if (preview is Resource.Success) {
itemView.home_none_padding?.apply { itemView.home_none_padding?.apply {
@ -604,6 +582,7 @@ class HomeParentItemAdapterPreview(
previewHeader?.isVisible = true previewHeader?.isVisible = true
} }
} }
else -> { else -> {
previewAdapter?.setItems(listOf(), false) previewAdapter?.setItems(listOf(), false)
previewViewpager?.setCurrentItem(0, false) previewViewpager?.setCurrentItem(0, false)
@ -614,13 +593,13 @@ class HomeParentItemAdapterPreview(
//previewViewpager?.postInvalidate() //previewViewpager?.postInvalidate()
} }
fun updateResume(resumeWatching: List<SearchResponse>) { private fun updateResume(resumeWatching: List<SearchResponse>) {
resumeHolder?.isVisible = resumeWatching.isNotEmpty() resumeHolder?.isVisible = resumeWatching.isNotEmpty()
resumeAdapter?.updateList(resumeWatching) resumeAdapter?.updateList(resumeWatching)
if (!isTvSettings()) { if (!isTvSettings()) {
itemView.home_watch_parent_item_title?.setOnClickListener { itemView.home_watch_parent_item_title?.setOnClickListener {
moreInfoClickCallback.invoke( viewModel.popup(
HomeViewModel.ExpandableHomepageList( HomeViewModel.ExpandableHomepageList(
HomePageList( HomePageList(
itemView.home_watch_parent_item_title?.text.toString(), itemView.home_watch_parent_item_title?.text.toString(),
@ -633,9 +612,10 @@ class HomeParentItemAdapterPreview(
} }
} }
fun updateBookmarks(data: Pair<Boolean, List<SearchResponse>>) { private fun updateBookmarks(data: Pair<Boolean, List<SearchResponse>>) {
bookmarkHolder?.isVisible = data.first val (visible, list) = data
bookmarkAdapter?.updateList(data.second) bookmarkHolder?.isVisible = visible
bookmarkAdapter?.updateList(list)
if (!isTvSettings()) { if (!isTvSettings()) {
itemView.home_bookmark_parent_item_title?.setOnClickListener { itemView.home_bookmark_parent_item_title?.setOnClickListener {
val items = toggleList.mapNotNull { it.first }.filter { it.isChecked } val items = toggleList.mapNotNull { it.first }.filter { it.isChecked }
@ -643,11 +623,11 @@ class HomeParentItemAdapterPreview(
val textSum = items val textSum = items
.mapNotNull { it.text }.joinToString() .mapNotNull { it.text }.joinToString()
moreInfoClickCallback.invoke( viewModel.popup(
HomeViewModel.ExpandableHomepageList( HomeViewModel.ExpandableHomepageList(
HomePageList( HomePageList(
textSum, textSum,
data.second, list,
false false
), 1, false ), 1, false
) )
@ -656,11 +636,12 @@ class HomeParentItemAdapterPreview(
} }
} }
fun setAvailableWatchStatusTypes(availableWatchStatusTypes: Pair<Set<WatchType>, Set<WatchType>>) { private fun setAvailableWatchStatusTypes(availableWatchStatusTypes: Pair<Set<WatchType>, Set<WatchType>>) {
val (visible, checked) = availableWatchStatusTypes
for ((chip, watch) in toggleList) { for ((chip, watch) in toggleList) {
chip?.apply { chip?.apply {
isVisible = availableWatchStatusTypes.second.contains(watch) isVisible = visible.contains(watch)
isChecked = availableWatchStatusTypes.first.contains(watch) isChecked = checked.contains(watch)
} }
} }
} }

View File

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.ui.home package com.lagradost.cloudstream3.ui.home
import android.os.Build
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -13,13 +14,24 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.context import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_FOCUSED
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.ui.search.SearchHelper
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.addProgramsToContinueWatching
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
@ -72,7 +84,7 @@ class HomeViewModel : ViewModel() {
} }
} }
private var repo: APIRepository? = null var repo: APIRepository? = null
private val _apiName = MutableLiveData<String>() private val _apiName = MutableLiveData<String>()
val apiName: LiveData<String> = _apiName val apiName: LiveData<String> = _apiName
@ -101,8 +113,14 @@ class HomeViewModel : ViewModel() {
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
val preview: LiveData<Resource<Pair<Boolean, List<LoadResponse>>>> = _preview val preview: LiveData<Resource<Pair<Boolean, List<LoadResponse>>>> = _preview
fun loadResumeWatching() = viewModelScope.launchSafe { private fun loadResumeWatching() = viewModelScope.launchSafe {
val resumeWatchingResult = getResumeWatching() val resumeWatchingResult = getResumeWatching()
if (isTrueTvSettings() && resumeWatchingResult != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ioSafe {
// this WILL crash on non tvs, so keep this inside a try catch
activity?.addProgramsToContinueWatching(resumeWatchingResult)
}
}
resumeWatchingResult?.let { resumeWatchingResult?.let {
_resumeWatching.postValue(it) _resumeWatching.postValue(it)
} }
@ -128,6 +146,10 @@ class HomeViewModel : ViewModel() {
currentWatchTypes.remove(WatchType.NONE) currentWatchTypes.remove(WatchType.NONE)
if (currentWatchTypes.size <= 0) { if (currentWatchTypes.size <= 0) {
setKey(
HOME_BOOKMARK_VALUE_LIST,
intArrayOf()
)
_availableWatchStatusTypes.postValue(setOf<WatchType>() to setOf()) _availableWatchStatusTypes.postValue(setOf<WatchType>() to setOf())
_bookmarks.postValue(Pair(false, ArrayList())) _bookmarks.postValue(Pair(false, ArrayList()))
return@launchSafe return@launchSafe
@ -135,7 +157,10 @@ class HomeViewModel : ViewModel() {
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first()) val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
//if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first()) //if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first())
setKey(
HOME_BOOKMARK_VALUE_LIST,
watchPrefNotNull.map { it.internalId }.toIntArray()
)
_availableWatchStatusTypes.postValue( _availableWatchStatusTypes.postValue(
Pair( Pair(
watchPrefNotNull, watchPrefNotNull,
@ -337,14 +362,80 @@ class HomeViewModel : ViewModel() {
logError(e) logError(e)
} }
} }
is Resource.Failure -> { is Resource.Failure -> {
_page.postValue(data!!) _page.postValue(data!!)
_preview.postValue(data!!) _preview.postValue(data!!)
} }
else -> Unit else -> Unit
} }
} }
fun click(callback: SearchClickCallback) {
if (callback.action == SEARCH_ACTION_FOCUSED) {
//focusCallback(callback.card)
} else {
SearchHelper.handleSearchClickCallback(callback)
}
}
private val _popup = MutableLiveData<ExpandableHomepageList?>(null)
val popup: LiveData<ExpandableHomepageList?> = _popup
fun popup(list: ExpandableHomepageList?) {
_popup.postValue(list)
}
private fun bookmarksUpdated(unused: Boolean) {
reloadStored()
}
private fun afterPluginsLoaded(forceReload: Boolean) {
loadAndCancel(getKey(USER_SELECTED_HOMEPAGE_API), forceReload)
}
private fun afterMainPluginsLoaded(unused: Boolean = false) {
loadAndCancel(getKey(USER_SELECTED_HOMEPAGE_API), false)
}
init {
MainActivity.bookmarksUpdatedEvent += ::bookmarksUpdated
MainActivity.afterPluginsLoadedEvent += ::afterPluginsLoaded
MainActivity.mainPluginsLoadedEvent += ::afterMainPluginsLoaded
}
override fun onCleared() {
MainActivity.bookmarksUpdatedEvent -= ::bookmarksUpdated
MainActivity.afterPluginsLoadedEvent -= ::afterPluginsLoaded
MainActivity.mainPluginsLoadedEvent -= ::afterMainPluginsLoaded
super.onCleared()
}
fun queryTextSubmit(query: String) {
QuickSearchFragment.pushSearch(
query,
repo?.name?.let { arrayOf(it) })
}
fun queryTextChange(newText: String) {
// do nothing
}
fun reloadStored() {
loadResumeWatching()
val list = EnumSet.noneOf(WatchType::class.java)
getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
list.addAll(it)
}
loadStoredData(list)
}
fun click(load: LoadClickCallback) {
loadResult(load.response.url, load.response.apiName, load.action)
}
fun loadAndCancel(preferredApiName: String?, forceReload: Boolean = true) = fun loadAndCancel(preferredApiName: String?, forceReload: Boolean = true) =
viewModelScope.launchSafe { viewModelScope.launchSafe {
// Since plugins are loaded in stages this function can get called multiple times. // Since plugins are loaded in stages this function can get called multiple times.

View File

@ -243,14 +243,12 @@ abstract class AbstractPlayerFragment(
fun showToast(message: String, gotoNext: Boolean = false) { fun showToast(message: String, gotoNext: Boolean = false) {
if (gotoNext && hasNextMirror()) { if (gotoNext && hasNextMirror()) {
showToast( showToast(
activity,
message, message,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
nextMirror() nextMirror()
} else { } else {
showToast( showToast(
activity,
context?.getString(R.string.no_links_found_toast) + "\n" + message, context?.getString(R.string.no_links_found_toast) + "\n" + message,
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
@ -461,7 +459,7 @@ abstract class AbstractPlayerFragment(
player_view?.resizeMode = type player_view?.resizeMode = type
if (showToast) if (showToast)
showToast(activity, resize.nameRes, Toast.LENGTH_SHORT) showToast(resize.nameRes, Toast.LENGTH_SHORT)
} }
override fun onStop() { override fun onStop() {

View File

@ -509,7 +509,6 @@ class GeneratorPlayer : FullScreenPlayer() {
selectSourceDialog?.dismissSafe() selectSourceDialog?.dismissSafe()
showToast( showToast(
activity,
String.format(ctx.getString(R.string.player_loaded_subtitles), subtitleData.name), String.format(ctx.getString(R.string.player_loaded_subtitles), subtitleData.name),
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
@ -889,7 +888,7 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
private fun noLinksFound() { private fun noLinksFound() {
showToast(activity, R.string.no_links_found_toast, Toast.LENGTH_SHORT) showToast(R.string.no_links_found_toast, Toast.LENGTH_SHORT)
activity?.popCurrentPage() activity?.popCurrentPage()
} }
@ -1357,7 +1356,7 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
is Resource.Failure -> { is Resource.Failure -> {
showToast(activity, it.errorString, Toast.LENGTH_LONG) showToast(it.errorString, Toast.LENGTH_LONG)
startPlayer() startPlayer()
} }
} }

View File

@ -19,6 +19,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.QuickSearchBinding import com.lagradost.cloudstream3.databinding.QuickSearchBinding
@ -45,6 +46,13 @@ class QuickSearchFragment : Fragment() {
const val AUTOSEARCH_KEY = "autosearch" const val AUTOSEARCH_KEY = "autosearch"
const val PROVIDER_KEY = "providers" const val PROVIDER_KEY = "providers"
fun pushSearch(
autoSearch: String? = null,
providers: Array<String>? = null
) {
pushSearch(activity, autoSearch, providers)
}
fun pushSearch( fun pushSearch(
activity: Activity?, activity: Activity?,
autoSearch: String? = null, autoSearch: String? = null,
@ -151,19 +159,20 @@ class QuickSearchFragment : Fragment() {
ArrayList(), ArrayList(),
this, this,
) { callback -> ) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
} }
} }
try { try {
binding?.quickSearch?.queryHint = getString(R.string.search_hint_site).format(providers?.first()) binding?.quickSearch?.queryHint =
getString(R.string.search_hint_site).format(providers?.first())
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
} }
} else { } else {
binding?.quickSearchMasterRecycler?.adapter = binding?.quickSearchMasterRecycler?.adapter =
ParentItemAdapter(mutableListOf(), { callback -> ParentItemAdapter(mutableListOf(), { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
//when (callback.action) { //when (callback.action) {
//SEARCH_ACTION_LOAD -> { //SEARCH_ACTION_LOAD -> {
// clickCallback?.invoke(callback) // clickCallback?.invoke(callback)
@ -235,11 +244,13 @@ class QuickSearchFragment : Fragment() {
searchExitIcon?.alpha = 1f searchExitIcon?.alpha = 1f
binding?.quickSearchLoadingBar?.alpha = 0f binding?.quickSearchLoadingBar?.alpha = 0f
} }
is Resource.Failure -> { is Resource.Failure -> {
// Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show() // Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
searchExitIcon?.alpha = 1f searchExitIcon?.alpha = 1f
binding?.quickSearchLoadingBar?.alpha = 0f binding?.quickSearchLoadingBar?.alpha = 0f
} }
is Resource.Loading -> { is Resource.Loading -> {
searchExitIcon?.alpha = 0f searchExitIcon?.alpha = 0f
binding?.quickSearchLoadingBar?.alpha = 1f binding?.quickSearchLoadingBar?.alpha = 1f

View File

@ -388,7 +388,7 @@ open class ResultFragment : ResultTrailerPlayer() {
) )
} }
else -> handleDownloadClick(activity, click) else -> handleDownloadClick(click)
} }
} }
} }
@ -575,7 +575,7 @@ open class ResultFragment : ResultTrailerPlayer() {
viewModel.handleAction(activity, episodeClick) viewModel.handleAction(activity, episodeClick)
}, },
{ downloadClickEvent -> { downloadClickEvent ->
handleDownloadClick(activity, downloadClickEvent) handleDownloadClick(downloadClickEvent)
} }
) )
@ -939,7 +939,7 @@ open class ResultFragment : ResultTrailerPlayer() {
val name = (viewModel.page.value as? Resource.Success)?.value?.title val name = (viewModel.page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(context) ?: "" ?: txt(R.string.no_data).asStringNull(context) ?: ""
showToast(activity, txt(message, name), Toast.LENGTH_SHORT) showToast(txt(message, name), Toast.LENGTH_SHORT)
} }
result_open_in_browser?.isVisible = d.url.startsWith("http") result_open_in_browser?.isVisible = d.url.startsWith("http")

View File

@ -187,7 +187,7 @@ class ResultFragmentPhone : ResultFragment() {
ArrayList(), ArrayList(),
result_recommendations, result_recommendations,
) { callback -> ) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
} }
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this) PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
@ -246,7 +246,6 @@ class ResultFragmentPhone : ResultFragment() {
if (!chromecastSupport) { if (!chromecastSupport) {
media_route_button?.setOnClickListener { media_route_button?.setOnClickListener {
CommonActivity.showToast( CommonActivity.showToast(
activity,
R.string.no_chromecast_support_toast, R.string.no_chromecast_support_toast,
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )

View File

@ -226,7 +226,7 @@ class ResultFragmentTv : ResultFragment() {
ArrayList(), ArrayList(),
result_recommendations, result_recommendations,
) { callback -> ) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
} }
} }
} }

View File

@ -748,7 +748,6 @@ class ResultViewModel2 : ViewModel() {
if (currentLinks.isEmpty()) { if (currentLinks.isEmpty()) {
main { main {
showToast( showToast(
activity,
R.string.no_links_found_toast, R.string.no_links_found_toast,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
@ -757,7 +756,6 @@ class ResultViewModel2 : ViewModel() {
} else { } else {
main { main {
showToast( showToast(
activity,
R.string.download_started, R.string.download_started,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
@ -1030,9 +1028,9 @@ class ResultViewModel2 : ViewModel() {
logError(t) logError(t)
main { main {
if (t is ActivityNotFoundException) { if (t is ActivityNotFoundException) {
showToast(activity, txt(R.string.app_not_found_error), Toast.LENGTH_LONG) showToast(txt(R.string.app_not_found_error), Toast.LENGTH_LONG)
} else { } else {
showToast(activity, t.toString(), Toast.LENGTH_LONG) showToast(t.toString(), Toast.LENGTH_LONG)
} }
} }
} }
@ -1285,7 +1283,6 @@ class ResultViewModel2 : ViewModel() {
) )
) )
showToast( showToast(
activity,
R.string.download_started, R.string.download_started,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
@ -1293,7 +1290,7 @@ class ResultViewModel2 : ViewModel() {
} }
ACTION_SHOW_TOAST -> { ACTION_SHOW_TOAST -> {
showToast(activity, R.string.play_episode_toast, Toast.LENGTH_SHORT) showToast(R.string.play_episode_toast, Toast.LENGTH_SHORT)
} }
ACTION_DOWNLOAD_EPISODE -> { ACTION_DOWNLOAD_EPISODE -> {
@ -1334,7 +1331,6 @@ class ResultViewModel2 : ViewModel() {
) )
} }
showToast( showToast(
activity,
R.string.download_started, R.string.download_started,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )
@ -1389,7 +1385,7 @@ class ResultViewModel2 : ViewModel() {
val link = result.links[index] val link = result.links[index]
val clip = ClipData.newPlainText(link.name, link.url) val clip = ClipData.newPlainText(link.name, link.url)
serviceClipboard.setPrimaryClip(clip) serviceClipboard.setPrimaryClip(clip)
showToast(act, R.string.copy_link_toast, Toast.LENGTH_SHORT) showToast(R.string.copy_link_toast, Toast.LENGTH_SHORT)
} }
} }
@ -1400,7 +1396,7 @@ class ResultViewModel2 : ViewModel() {
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> { ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
loadLinks(click.data, isVisible = true, isCasting = true) { links -> loadLinks(click.data, isVisible = true, isCasting = true) { links ->
if (links.links.isEmpty()) { if (links.links.isEmpty()) {
showToast(activity, R.string.no_links_found_toast, Toast.LENGTH_SHORT) showToast(R.string.no_links_found_toast, Toast.LENGTH_SHORT)
return@loadLinks return@loadLinks
} }

View File

@ -214,7 +214,7 @@ class SearchFragment : Fragment() {
ArrayList(), ArrayList(),
searchAutofitResults, searchAutofitResults,
) { callback -> ) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
} }
@ -491,7 +491,7 @@ class SearchFragment : Fragment() {
val masterAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = val masterAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
ParentItemAdapter(mutableListOf(), { callback -> ParentItemAdapter(mutableListOf(), { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(callback)
}, { item -> }, { item ->
bottomSheetDialog = activity?.loadHomepageList(item, dismissCallback = { bottomSheetDialog = activity?.loadHomepageList(item, dismissCallback = {
bottomSheetDialog = null bottomSheetDialog = null

View File

@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.search
import android.app.Activity import android.app.Activity
import android.widget.Toast import android.widget.Toast
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
@ -15,21 +16,21 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadHelper
object SearchHelper { object SearchHelper {
fun handleSearchClickCallback(activity: Activity?, callback: SearchClickCallback) { fun handleSearchClickCallback(callback: SearchClickCallback) {
val card = callback.card val card = callback.card
when (callback.action) { when (callback.action) {
SEARCH_ACTION_LOAD -> { SEARCH_ACTION_LOAD -> {
activity.loadSearchResult(card) loadSearchResult(card)
} }
SEARCH_ACTION_PLAY_FILE -> { SEARCH_ACTION_PLAY_FILE -> {
if (card is DataStoreHelper.ResumeWatchingResult) { if (card is DataStoreHelper.ResumeWatchingResult) {
val id = card.id val id = card.id
if(id == null) { if(id == null) {
showToast(activity, R.string.error_invalid_id, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_id, Toast.LENGTH_SHORT)
} else { } else {
if (card.isFromDownload) { if (card.isFromDownload) {
handleDownloadClick( handleDownloadClick(
activity, DownloadClickEvent( DownloadClickEvent(
DOWNLOAD_ACTION_PLAY_FILE, DOWNLOAD_ACTION_PLAY_FILE,
VideoDownloadHelper.DownloadEpisodeCached( VideoDownloadHelper.DownloadEpisodeCached(
card.name, card.name,
@ -45,12 +46,11 @@ object SearchHelper {
) )
) )
} else { } else {
activity.loadSearchResult(card, START_ACTION_LOAD_EP, id) loadSearchResult(card, START_ACTION_LOAD_EP, id)
} }
} }
} else { } else {
handleSearchClickCallback( handleSearchClickCallback(
activity,
SearchClickCallback(SEARCH_ACTION_LOAD, callback.view, -1, callback.card) SearchClickCallback(SEARCH_ACTION_LOAD, callback.view, -1, callback.card)
) )
} }
@ -60,10 +60,10 @@ object SearchHelper {
(activity as? MainActivity?)?.apply { (activity as? MainActivity?)?.apply {
loadPopup(callback.card) loadPopup(callback.card)
} ?: kotlin.run { } ?: kotlin.run {
showToast(activity, callback.card.name, Toast.LENGTH_SHORT) showToast(callback.card.name, Toast.LENGTH_SHORT)
} }
} else { } else {
showToast(activity, callback.card.name, Toast.LENGTH_SHORT) showToast(callback.card.name, Toast.LENGTH_SHORT)
} }
} }
} }

View File

@ -216,7 +216,6 @@ class SettingsAccount : PreferenceFragmentCompat() {
activity.runOnUiThread { activity.runOnUiThread {
try { try {
showToast( showToast(
activity,
activity.getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail) activity.getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail)
.format( .format(
api.name api.name

View File

@ -213,7 +213,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
val lang = binding.siteLangInput.text?.toString() val lang = binding.siteLangInput.text?.toString()
val realLang = if (lang.isNullOrBlank()) provider.lang else lang val realLang = if (lang.isNullOrBlank()) provider.lang else lang
if (url.isNullOrBlank() || name.isNullOrBlank() || realLang.length != 2) { if (url.isNullOrBlank() || name.isNullOrBlank() || realLang.length != 2) {
showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT)
return@setOnClickListener return@setOnClickListener
} }

View File

@ -95,7 +95,7 @@ class SettingsUpdates : PreferenceFragmentCompat() {
serviceClipboard.setPrimaryClip(clip) serviceClipboard.setPrimaryClip(clip)
dialog.dismissSafe(activity) dialog.dismissSafe(activity)
} catch (e: TransactionTooLargeException) { } catch (e: TransactionTooLargeException) {
showToast(activity, R.string.clipboard_too_large) showToast(R.string.clipboard_too_large)
} }
} }
binding.clearBtt.setOnClickListener { binding.clearBtt.setOnClickListener {
@ -158,7 +158,6 @@ class SettingsUpdates : PreferenceFragmentCompat() {
if (activity?.runAutoUpdate(false) == false) { if (activity?.runAutoUpdate(false) == false) {
activity?.runOnUiThread { activity?.runOnUiThread {
showToast( showToast(
activity,
R.string.no_update_found, R.string.no_update_found,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
) )

View File

@ -211,7 +211,7 @@ class ExtensionsFragment : Fragment() {
?.let { it1 -> RepositoryManager.parseRepoUrl(it1) } ?.let { it1 -> RepositoryManager.parseRepoUrl(it1) }
if (url.isNullOrBlank()) { if (url.isNullOrBlank()) {
main { main {
showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT) showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT)
} }
} else { } else {
val fixedName = if (!name.isNullOrBlank()) name val fixedName = if (!name.isNullOrBlank()) name

View File

@ -86,7 +86,6 @@ class PluginsViewModel : ViewModel() {
}.also { list -> }.also { list ->
main { main {
showToast( showToast(
activity,
if (list.isEmpty()) { if (list.isEmpty()) {
txt( txt(
R.string.batch_download_nothing_to_download_format, R.string.batch_download_nothing_to_download_format,
@ -113,7 +112,6 @@ class PluginsViewModel : ViewModel() {
}.main { list -> }.main { list ->
if (list.any { it }) { if (list.any { it }) {
showToast( showToast(
activity,
txt( txt(
R.string.batch_download_finish_format, R.string.batch_download_finish_format,
list.count { it }, list.count { it },
@ -123,7 +121,7 @@ class PluginsViewModel : ViewModel() {
) )
viewModel?.updatePluginListPrivate(activity, repositoryUrl) viewModel?.updatePluginListPrivate(activity, repositoryUrl)
} else if (list.isNotEmpty()) { } else if (list.isNotEmpty()) {
showToast(activity, R.string.download_failed, Toast.LENGTH_SHORT) showToast(R.string.download_failed, Toast.LENGTH_SHORT)
} }
} }
} }
@ -166,9 +164,9 @@ class PluginsViewModel : ViewModel() {
runOnMainThread { runOnMainThread {
if (success) if (success)
showToast(activity, message, Toast.LENGTH_SHORT) showToast(message, Toast.LENGTH_SHORT)
else else
showToast(activity, R.string.error, Toast.LENGTH_SHORT) showToast(R.string.error, Toast.LENGTH_SHORT)
} }
if (success) if (success)

View File

@ -194,7 +194,7 @@ class ChromecastSubtitlesFragment : Fragment() {
this.setOnLongClickListener { this.setOnLongClickListener {
it.context.setColor(id, null) it.context.setColor(id, null)
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }
} }
@ -252,7 +252,7 @@ class ChromecastSubtitlesFragment : Fragment() {
binding?.subsEdgeType?.setOnLongClickListener { binding?.subsEdgeType?.setOnLongClickListener {
state.edgeType = defaultState.edgeType state.edgeType = defaultState.edgeType
it.context.updateState() it.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }
@ -293,7 +293,7 @@ class ChromecastSubtitlesFragment : Fragment() {
binding?.subsFontSize?.setOnLongClickListener { _ -> binding?.subsFontSize?.setOnLongClickListener { _ ->
state.fontScale = defaultState.fontScale state.fontScale = defaultState.fontScale
//textView.context.updateState() // font size not changed //textView.context.updateState() // font size not changed
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }

View File

@ -272,7 +272,7 @@ class SubtitlesFragment : Fragment() {
this.setOnLongClickListener { this.setOnLongClickListener {
it.context.setColor(id, null) it.context.setColor(id, null)
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }
} }
@ -322,7 +322,7 @@ class SubtitlesFragment : Fragment() {
subsSubtitleElevation.setOnLongClickListener { subsSubtitleElevation.setOnLongClickListener {
state.elevation = DEF_SUBS_ELEVATION state.elevation = DEF_SUBS_ELEVATION
it.context.updateState() it.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }
@ -367,7 +367,7 @@ class SubtitlesFragment : Fragment() {
subsEdgeType.setOnLongClickListener { subsEdgeType.setOnLongClickListener {
state.edgeType = CaptionStyleCompat.EDGE_TYPE_OUTLINE state.edgeType = CaptionStyleCompat.EDGE_TYPE_OUTLINE
it.context.updateState() it.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT) showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true return@setOnLongClickListener true
} }

View File

@ -47,6 +47,7 @@ import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.common.wrappers.Wrappers import com.google.android.gms.common.wrappers.Wrappers
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -198,7 +199,11 @@ object AppUtils {
animation.start() animation.start()
} }
fun Context.createNotificationChannel(channelId: String, channelName: String, description: String) { fun Context.createNotificationChannel(
channelId: String,
channelName: String,
description: String
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = val channel =
@ -288,6 +293,7 @@ object AppUtils {
// https://github.com/googlearchive/leanback-homescreen-channels/blob/master/app/src/main/java/com/google/android/tvhomescreenchannels/SampleTvProvider.java // https://github.com/googlearchive/leanback-homescreen-channels/blob/master/app/src/main/java/com/google/android/tvhomescreenchannels/SampleTvProvider.java
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
@Throws
@WorkerThread @WorkerThread
suspend fun Context.addProgramsToContinueWatching(data: List<DataStoreHelper.ResumeWatchingResult>) { suspend fun Context.addProgramsToContinueWatching(data: List<DataStoreHelper.ResumeWatchingResult>) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
@ -369,7 +375,6 @@ object AppUtils {
) )
main { main {
showToast( showToast(
this@loadRepository,
getString(R.string.player_loaded_subtitles, repo.name), getString(R.string.player_loaded_subtitles, repo.name),
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
@ -577,6 +582,15 @@ object AppUtils {
} }
} }
fun loadResult(
url: String,
apiName: String,
startAction: Int = 0,
startValue: Int = 0
) {
(activity as FragmentActivity?)?.loadResult(url, apiName, startAction, startValue)
}
fun FragmentActivity.loadResult( fun FragmentActivity.loadResult(
url: String, url: String,
apiName: String, apiName: String,
@ -592,6 +606,14 @@ object AppUtils {
} }
} }
fun loadSearchResult(
card: SearchResponse,
startAction: Int = 0,
startValue: Int? = null,
) {
activity?.loadSearchResult(card, startAction, startValue)
}
fun Activity?.loadSearchResult( fun Activity?.loadSearchResult(
card: SearchResponse, card: SearchResponse,
startAction: Int = 0, startAction: Int = 0,
@ -776,12 +798,12 @@ object AppUtils {
return networkInfo.any { return networkInfo.any {
conManager.getNetworkCapabilities(it) conManager.getNetworkCapabilities(it)
?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true ?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true
} && } &&
!networkInfo.any { !networkInfo.any {
conManager.getNetworkCapabilities(it) conManager.getNetworkCapabilities(it)
?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true ?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true
} }
} }
private fun Activity?.cacheClass(clazz: String?) { private fun Activity?.cacheClass(clazz: String?) {

View File

@ -149,7 +149,7 @@ object BackupUtils {
fun FragmentActivity.backup() { fun FragmentActivity.backup() {
try { try {
if (!checkWrite()) { if (!checkWrite()) {
showToast(this, getString(R.string.backup_failed), Toast.LENGTH_LONG) showToast(getString(R.string.backup_failed), Toast.LENGTH_LONG)
requestRW() requestRW()
return return
} }
@ -201,7 +201,6 @@ object BackupUtils {
printStream.close() printStream.close()
showToast( showToast(
this,
R.string.backup_success, R.string.backup_success,
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
@ -209,7 +208,6 @@ object BackupUtils {
logError(e) logError(e)
try { try {
showToast( showToast(
this,
getString(R.string.backup_failed_error_format).format(e.toString()), getString(R.string.backup_failed_error_format).format(e.toString()),
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
@ -243,7 +241,6 @@ object BackupUtils {
logError(e) logError(e)
main { // smth can fail in .format main { // smth can fail in .format
showToast( showToast(
activity,
getString(R.string.restore_failed_format).format(e.toString()) getString(R.string.restore_failed_format).format(e.toString())
) )
} }
@ -270,7 +267,7 @@ object BackupUtils {
) )
) )
} catch (e: Exception) { } catch (e: Exception) {
showToast(this, e.message) showToast(e.message)
logError(e) logError(e)
} }
} }

View File

@ -300,7 +300,7 @@ class InAppUpdater {
// Forcefully start any delayed installations // Forcefully start any delayed installations
if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton
showToast(context, R.string.download_started, Toast.LENGTH_LONG) showToast(R.string.download_started, Toast.LENGTH_LONG)
// Check if the setting hasn't been changed // Check if the setting hasn't been changed
if (settingsManager.getInt( if (settingsManager.getInt(
@ -335,7 +335,6 @@ class InAppUpdater {
if (!downloadUpdate(update.updateURL)) if (!downloadUpdate(update.updateURL))
runOnUiThread { runOnUiThread {
showToast( showToast(
context,
R.string.download_failed, R.string.download_failed,
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )

View File

@ -46,6 +46,7 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions.bitmapTransform import com.bumptech.glide.request.RequestOptions.bitmapTransform
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.result.UiImage import com.lagradost.cloudstream3.ui.result.UiImage
@ -554,7 +555,7 @@ object UIHelper {
} }
fun Dialog?.dismissSafe() { fun Dialog?.dismissSafe() {
if (this?.isShowing == true) { if (this?.isShowing == true && activity?.isFinishing != true) {
this.dismiss() this.dismiss()
} }
} }