mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
migrated some items to viewbindings + removed Some<T>
This commit is contained in:
parent
927453d9fe
commit
05a0d3cd81
46 changed files with 1565 additions and 1264 deletions
|
@ -28,6 +28,11 @@ android {
|
|||
testOptions {
|
||||
unitTests.isReturnDefaultValues = true
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enable = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
create("prerelease") {
|
||||
if (prereleaseStoreFile != null) {
|
||||
|
|
|
@ -57,32 +57,6 @@ fun <T> LifecycleOwner.observeNullable(liveData: LiveData<T>, action: (t: T) ->
|
|||
liveData.observe(this) { action(it) }
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> some(value: T?): Some<T> {
|
||||
return if (value == null) {
|
||||
Some.None
|
||||
} else {
|
||||
Some.Success(value)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Some<out T> {
|
||||
data class Success<out T>(val value: T) : Some<T>()
|
||||
object None : Some<Nothing>()
|
||||
|
||||
override fun toString(): String {
|
||||
return when (this) {
|
||||
is None -> "None"
|
||||
is Success -> "Some(${value.toString()})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ResourceSome<out T> {
|
||||
data class Success<out T>(val value: T) : ResourceSome<T>()
|
||||
object None : ResourceSome<Nothing>()
|
||||
data class Loading(val data: Any? = null) : ResourceSome<Nothing>()
|
||||
}
|
||||
|
||||
sealed class Resource<out T> {
|
||||
data class Success<out T>(val value: T) : Resource<T>()
|
||||
data class Failure(
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentChildDownloadsBinding
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
|
@ -15,13 +16,12 @@ import com.lagradost.cloudstream3.utils.DataStore.getKeys
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import kotlinx.android.synthetic.main.fragment_child_downloads.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DownloadChildFragment : Fragment() {
|
||||
companion object {
|
||||
fun newInstance(headerName: String, folder: String) : Bundle {
|
||||
fun newInstance(headerName: String, folder: String): Bundle {
|
||||
return Bundle().apply {
|
||||
putString("folder", folder)
|
||||
putString("name", headerName)
|
||||
|
@ -30,13 +30,21 @@ class DownloadChildFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
(download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter()
|
||||
(binding?.downloadChildList?.adapter as DownloadChildAdapter?)?.killAdapter()
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_child_downloads, container, false)
|
||||
var binding: FragmentChildDownloadsBinding? = null
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val localBinding = FragmentChildDownloadsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.fragment_child_downloads, container, false)
|
||||
}
|
||||
|
||||
private fun updateList(folder: String) = main {
|
||||
|
@ -50,14 +58,15 @@ class DownloadChildFragment : Fragment() {
|
|||
?: return@mapNotNull null
|
||||
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
|
||||
}
|
||||
}.sortedBy { it.data.episode + (it.data.season?: 0)*100000 }
|
||||
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
|
||||
if (eps.isEmpty()) {
|
||||
activity?.onBackPressed()
|
||||
return@main
|
||||
}
|
||||
|
||||
(download_child_list?.adapter as DownloadChildAdapter? ?: return@main).cardList = eps
|
||||
download_child_list?.adapter?.notifyDataSetChanged()
|
||||
(binding?.downloadChildList?.adapter as DownloadChildAdapter? ?: return@main).cardList =
|
||||
eps
|
||||
binding?.downloadChildList?.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,14 +81,17 @@ class DownloadChildFragment : Fragment() {
|
|||
activity?.onBackPressed() // TODO FIX
|
||||
return
|
||||
}
|
||||
context?.fixPaddingStatusbar(download_child_root)
|
||||
fixPaddingStatusbar(binding?.downloadChildRoot)
|
||||
|
||||
download_child_toolbar.title = name
|
||||
download_child_toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
|
||||
download_child_toolbar.setNavigationOnClickListener {
|
||||
activity?.onBackPressed()
|
||||
binding?.downloadChildToolbar?.apply {
|
||||
title = name
|
||||
setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
|
||||
setNavigationOnClickListener {
|
||||
activity?.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||
DownloadChildAdapter(
|
||||
ArrayList(),
|
||||
|
@ -88,7 +100,7 @@ class DownloadChildFragment : Fragment() {
|
|||
}
|
||||
|
||||
downloadDeleteEventListener = { id: Int ->
|
||||
val list = (download_child_list?.adapter as DownloadChildAdapter?)?.cardList
|
||||
val list = (binding?.downloadChildList?.adapter as DownloadChildAdapter?)?.cardList
|
||||
if (list != null) {
|
||||
if (list.any { it.data.id == id }) {
|
||||
updateList(folder)
|
||||
|
@ -98,8 +110,8 @@ class DownloadChildFragment : Fragment() {
|
|||
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||
|
||||
download_child_list.adapter = adapter
|
||||
download_child_list.layoutManager = GridLayoutManager(context, 1)
|
||||
binding?.downloadChildList?.adapter = adapter
|
||||
binding?.downloadChildList?.layoutManager = GridLayoutManager(context, 1)
|
||||
|
||||
updateList(folder)
|
||||
}
|
||||
|
|
|
@ -34,10 +34,10 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import kotlinx.android.synthetic.main.fragment_downloads.*
|
||||
import kotlinx.android.synthetic.main.stream_input.*
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
||||
import com.lagradost.cloudstream3.databinding.StreamInputBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.ui.player.BasicLink
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
|
@ -60,8 +60,8 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
private fun setList(list: List<VisualDownloadHeaderCached>) {
|
||||
main {
|
||||
(download_list?.adapter as DownloadHeaderAdapter?)?.cardList = list
|
||||
download_list?.adapter?.notifyDataSetChanged()
|
||||
(binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList = list
|
||||
binding?.downloadList?.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,10 +70,13 @@ class DownloadFragment : Fragment() {
|
|||
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
|
||||
downloadDeleteEventListener = null
|
||||
}
|
||||
(download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
|
||||
(binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.killAdapter()
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
var binding : FragmentDownloadsBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -82,7 +85,9 @@ class DownloadFragment : Fragment() {
|
|||
downloadsViewModel =
|
||||
ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
|
||||
return inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||
val localBinding = FragmentDownloadsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||
}
|
||||
|
||||
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
|
||||
|
@ -92,36 +97,40 @@ class DownloadFragment : Fragment() {
|
|||
hideKeyboard()
|
||||
|
||||
observe(downloadsViewModel.noDownloadsText) {
|
||||
text_no_downloads.text = it
|
||||
binding?.textNoDownloads?.text = it
|
||||
}
|
||||
observe(downloadsViewModel.headerCards) {
|
||||
setList(it)
|
||||
download_loading.isVisible = false
|
||||
binding?.downloadLoading?.isVisible = false
|
||||
}
|
||||
observe(downloadsViewModel.availableBytes) {
|
||||
download_free_txt?.text =
|
||||
binding?.downloadFreeTxt?.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.free_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
download_free?.setLayoutWidth(it)
|
||||
binding?.downloadFree?.setLayoutWidth(it)
|
||||
}
|
||||
observe(downloadsViewModel.usedBytes) {
|
||||
download_used_txt?.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.used_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
download_used?.setLayoutWidth(it)
|
||||
download_storage_appbar?.isVisible = it > 0
|
||||
binding?.apply {
|
||||
downloadUsedTxt.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.used_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
downloadUsed.setLayoutWidth(it)
|
||||
downloadStorageAppbar.isVisible = it > 0
|
||||
}
|
||||
}
|
||||
observe(downloadsViewModel.downloadBytes) {
|
||||
download_app_txt?.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.app_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
download_app?.setLayoutWidth(it)
|
||||
binding?.apply {
|
||||
downloadAppTxt.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.app_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
downloadApp.setLayoutWidth(it)
|
||||
}
|
||||
}
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||
|
@ -164,7 +173,7 @@ class DownloadFragment : Fragment() {
|
|||
)
|
||||
|
||||
downloadDeleteEventListener = { id ->
|
||||
val list = (download_list?.adapter as DownloadHeaderAdapter?)?.cardList
|
||||
val list = (binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList
|
||||
if (list != null) {
|
||||
if (list.any { it.data.id == id }) {
|
||||
context?.let { ctx ->
|
||||
|
@ -177,31 +186,36 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||
|
||||
download_list?.adapter = adapter
|
||||
download_list?.layoutManager = GridLayoutManager(context, 1)
|
||||
binding?.downloadList?.apply {
|
||||
this.adapter = adapter
|
||||
layoutManager = GridLayoutManager(context, 1)
|
||||
}
|
||||
|
||||
// Should be visible in emulator layout
|
||||
download_stream_button?.isGone = isTrueTvSettings()
|
||||
download_stream_button?.setOnClickListener {
|
||||
binding?.downloadStreamButton?.isGone = isTrueTvSettings()
|
||||
binding?.downloadStreamButton?.setOnClickListener {
|
||||
val dialog =
|
||||
Dialog(it.context ?: return@setOnClickListener, R.style.AlertDialogCustom)
|
||||
dialog.setContentView(R.layout.stream_input)
|
||||
|
||||
val binding = StreamInputBinding.inflate(dialog.layoutInflater)
|
||||
|
||||
dialog.setContentView(binding.root)
|
||||
|
||||
dialog.show()
|
||||
|
||||
// If user has clicked the switch do not interfere
|
||||
var preventAutoSwitching = false
|
||||
dialog.hls_switch?.setOnClickListener {
|
||||
binding.hlsSwitch.setOnClickListener {
|
||||
preventAutoSwitching = true
|
||||
}
|
||||
|
||||
fun activateSwitchOnHls(text: String?) {
|
||||
dialog.hls_switch?.isChecked = normalSafeApiCall {
|
||||
binding.hlsSwitch.isChecked = normalSafeApiCall {
|
||||
URI(text).path?.substringAfterLast(".")?.contains("m3u")
|
||||
} == true
|
||||
}
|
||||
|
||||
dialog.stream_referer?.doOnTextChanged { text, _, _, _ ->
|
||||
binding.streamReferer.doOnTextChanged { text, _, _, _ ->
|
||||
if (!preventAutoSwitching)
|
||||
activateSwitchOnHls(text?.toString())
|
||||
}
|
||||
|
@ -210,16 +224,16 @@ class DownloadFragment : Fragment() {
|
|||
0
|
||||
)?.text?.toString()?.let { copy ->
|
||||
val fixedText = copy.trim()
|
||||
dialog.stream_url?.setText(fixedText)
|
||||
binding.streamUrl.setText(fixedText)
|
||||
activateSwitchOnHls(fixedText)
|
||||
}
|
||||
|
||||
dialog.apply_btt?.setOnClickListener {
|
||||
val url = dialog.stream_url.text?.toString()
|
||||
binding.applyBtt.setOnClickListener {
|
||||
val url = binding.streamUrl.text?.toString()
|
||||
if (url.isNullOrEmpty()) {
|
||||
showToast(activity, R.string.error_invalid_url, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
val referer = dialog.stream_referer.text?.toString()
|
||||
val referer = binding.streamReferer.text?.toString()
|
||||
|
||||
activity?.navigate(
|
||||
R.id.global_to_navigation_player,
|
||||
|
@ -228,7 +242,7 @@ class DownloadFragment : Fragment() {
|
|||
listOf(BasicLink(url)),
|
||||
extract = true,
|
||||
referer = referer,
|
||||
isM3u8 = dialog.hls_switch?.isChecked
|
||||
isM3u8 = binding.hlsSwitch.isChecked
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -237,22 +251,22 @@ class DownloadFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
dialog.cancel_btt?.setOnClickListener {
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
download_list?.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
binding?.downloadList?.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
download_stream_button?.shrink() // hide
|
||||
binding?.downloadStreamButton?.shrink() // hide
|
||||
} else if (dy < -5) {
|
||||
download_stream_button?.extend() // show
|
||||
binding?.downloadStreamButton?.extend() // show
|
||||
}
|
||||
}
|
||||
}
|
||||
downloadsViewModel.updateList(requireContext())
|
||||
|
||||
context?.fixPaddingStatusbar(download_root)
|
||||
fixPaddingStatusbar(binding?.downloadRoot)
|
||||
}
|
||||
}
|
|
@ -34,12 +34,15 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
|||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.bookmarksUpdatedEvent
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.mainPluginsLoadedEvent
|
||||
import com.lagradost.cloudstream3.databinding.FragmentHomeBinding
|
||||
import com.lagradost.cloudstream3.databinding.HomeEpisodesExpandedBinding
|
||||
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
||||
import com.lagradost.cloudstream3.databinding.TvtypesChipsBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
||||
import com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||
import com.lagradost.cloudstream3.ui.search.*
|
||||
|
@ -64,24 +67,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
||||
import kotlinx.android.synthetic.main.activity_main_tv.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_api_fab
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_change_api_loading
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_loading
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_loading_error
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_loading_shimmer
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_loading_statusbar
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_master_recycler
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_reload_connection_open_in_browser
|
||||
import kotlinx.android.synthetic.main.fragment_home.home_reload_connectionerror
|
||||
import kotlinx.android.synthetic.main.fragment_home.result_error_text
|
||||
import kotlinx.android.synthetic.main.fragment_home_tv.*
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
import kotlinx.android.synthetic.main.fragment_search.*
|
||||
import kotlinx.android.synthetic.main.home_episodes_expanded.*
|
||||
import kotlinx.android.synthetic.main.tvtypes_chips.*
|
||||
import kotlinx.android.synthetic.main.tvtypes_chips.view.*
|
||||
|
||||
import java.util.*
|
||||
|
||||
|
||||
|
@ -125,22 +111,26 @@ class HomeFragment : Fragment() {
|
|||
expand: HomeViewModel.ExpandableHomepageList,
|
||||
deleteCallback: (() -> Unit)? = null,
|
||||
expandCallback: (suspend (String) -> HomeViewModel.ExpandableHomepageList?)? = null,
|
||||
dismissCallback : (() -> Unit),
|
||||
dismissCallback: (() -> Unit),
|
||||
): BottomSheetDialog {
|
||||
val context = this
|
||||
val bottomSheetDialogBuilder = BottomSheetDialog(context)
|
||||
|
||||
bottomSheetDialogBuilder.setContentView(R.layout.home_episodes_expanded)
|
||||
val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
||||
val binding: HomeEpisodesExpandedBinding = HomeEpisodesExpandedBinding.inflate(
|
||||
bottomSheetDialogBuilder.layoutInflater,
|
||||
null,
|
||||
false
|
||||
)
|
||||
bottomSheetDialogBuilder.setContentView(binding.root)
|
||||
//val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
||||
|
||||
//title.findViewTreeLifecycleOwner().lifecycle.addObserver()
|
||||
|
||||
val item = expand.list
|
||||
title.text = item.name
|
||||
val recycle =
|
||||
bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
||||
val titleHolder =
|
||||
bottomSheetDialogBuilder.findViewById<FrameLayout>(R.id.home_expanded_drag_down)!!
|
||||
binding.homeExpandedText.text = item.name
|
||||
// val recycle =
|
||||
// bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
||||
//val titleHolder =
|
||||
// bottomSheetDialogBuilder.findViewById<FrameLayout>(R.id.home_expanded_drag_down)!!
|
||||
|
||||
// main {
|
||||
//(bottomSheetDialogBuilder.ownerActivity as androidx.fragment.app.FragmentActivity?)?.supportFragmentManager?.fragments?.lastOrNull()?.viewLifecycleOwner?.apply {
|
||||
|
@ -159,10 +149,10 @@ class HomeFragment : Fragment() {
|
|||
// })
|
||||
//}
|
||||
// }
|
||||
val delete = bottomSheetDialogBuilder.home_expanded_delete
|
||||
delete.isGone = deleteCallback == null
|
||||
//val delete = bottomSheetDialogBuilder.home_expanded_delete
|
||||
binding.homeExpandedDelete.isGone = deleteCallback == null
|
||||
if (deleteCallback != null) {
|
||||
delete.setOnClickListener {
|
||||
binding.homeExpandedDelete.setOnClickListener {
|
||||
try {
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
|
||||
val dialogClickListener =
|
||||
|
@ -172,6 +162,7 @@ class HomeFragment : Fragment() {
|
|||
deleteCallback.invoke()
|
||||
bottomSheetDialogBuilder.dismissSafe(this)
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEGATIVE -> {}
|
||||
}
|
||||
}
|
||||
|
@ -191,26 +182,27 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
titleHolder.setOnClickListener {
|
||||
binding.homeExpandedDragDown.setOnClickListener {
|
||||
bottomSheetDialogBuilder.dismissSafe(this)
|
||||
}
|
||||
|
||||
|
||||
// Span settings
|
||||
recycle.spanCount = currentSpan
|
||||
binding.homeExpandedRecycler.spanCount = currentSpan
|
||||
|
||||
recycle.adapter = SearchAdapter(item.list.toMutableList(), recycle) { callback ->
|
||||
handleSearchClickCallback(this, callback)
|
||||
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.dismissSafe(this)
|
||||
binding.homeExpandedRecycler.adapter =
|
||||
SearchAdapter(item.list.toMutableList(), binding.homeExpandedRecycler) { callback ->
|
||||
handleSearchClickCallback(this, callback)
|
||||
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.dismissSafe(this)
|
||||
}
|
||||
}.apply {
|
||||
hasNext = expand.hasNext
|
||||
}
|
||||
}.apply {
|
||||
hasNext = expand.hasNext
|
||||
}
|
||||
|
||||
recycle.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
binding.homeExpandedRecycler.addOnScrollListener(object :
|
||||
RecyclerView.OnScrollListener() {
|
||||
var expandCount = 0
|
||||
val name = expand.list.name
|
||||
|
||||
|
@ -238,7 +230,7 @@ class HomeFragment : Fragment() {
|
|||
})
|
||||
|
||||
val spanListener = { span: Int ->
|
||||
recycle.spanCount = span
|
||||
binding.homeExpandedRecycler.spanCount = span
|
||||
//(recycle.adapter as SearchAdapter).notifyDataSetChanged()
|
||||
}
|
||||
|
||||
|
@ -280,19 +272,19 @@ class HomeFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
private fun getPairList(header: ChipGroup) = getPairList(
|
||||
header.home_select_anime,
|
||||
header.home_select_cartoons,
|
||||
header.home_select_tv_series,
|
||||
header.home_select_documentaries,
|
||||
header.home_select_movies,
|
||||
header.home_select_asian,
|
||||
header.home_select_livestreams,
|
||||
header.home_select_nsfw,
|
||||
header.home_select_others
|
||||
private fun getPairList(header: TvtypesChipsBinding) = getPairList(
|
||||
header.homeSelectAnime,
|
||||
header.homeSelectCartoons,
|
||||
header.homeSelectTvSeries,
|
||||
header.homeSelectDocumentaries,
|
||||
header.homeSelectMovies,
|
||||
header.homeSelectAsian,
|
||||
header.homeSelectLivestreams,
|
||||
header.homeSelectNsfw,
|
||||
header.homeSelectOthers
|
||||
)
|
||||
|
||||
fun validateChips(header: ChipGroup?, validTypes: List<TvType>) {
|
||||
fun validateChips(header: TvtypesChipsBinding?, validTypes: List<TvType>) {
|
||||
if (header == null) return
|
||||
val pairList = getPairList(header)
|
||||
for ((button, types) in pairList) {
|
||||
|
@ -301,7 +293,7 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
fun updateChips(header: ChipGroup?, selectedTypes: List<TvType>) {
|
||||
fun updateChips(header: TvtypesChipsBinding?, selectedTypes: List<TvType>) {
|
||||
if (header == null) return
|
||||
val pairList = getPairList(header)
|
||||
for ((button, types) in pairList) {
|
||||
|
@ -311,7 +303,7 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
fun bindChips(
|
||||
header: ChipGroup?,
|
||||
header: TvtypesChipsBinding?,
|
||||
selectedTypes: List<TvType>,
|
||||
validTypes: List<TvType>,
|
||||
callback: (List<TvType>) -> Unit
|
||||
|
@ -344,7 +336,13 @@ class HomeFragment : Fragment() {
|
|||
BottomSheetDialog(this)
|
||||
|
||||
builder.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
builder.setContentView(R.layout.home_select_mainpage)
|
||||
val binding: HomeSelectMainpageBinding = HomeSelectMainpageBinding.inflate(
|
||||
builder.layoutInflater,
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
builder.setContentView(binding.root)
|
||||
builder.show()
|
||||
builder.let { dialog ->
|
||||
val isMultiLang = getApiProviderLangSettings().let { set ->
|
||||
|
@ -408,7 +406,7 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
bindChips(
|
||||
dialog.home_select_group,
|
||||
binding.tvtypesChipsScroll.tvtypesChips,
|
||||
preSelectedTypes,
|
||||
validAPIs.flatMap { it.supportedTypes }.distinct()
|
||||
) { list ->
|
||||
|
@ -423,6 +421,9 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
var binding: FragmentHomeBinding? = null
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -433,11 +434,24 @@ class HomeFragment : Fragment() {
|
|||
bottomSheetDialog?.ownShow()
|
||||
val layout =
|
||||
if (isTvSettings()) R.layout.fragment_home_tv else R.layout.fragment_home
|
||||
return inflater.inflate(layout, container, false)
|
||||
|
||||
/* val binding = FragmentHomeTvBinding.inflate(layout, container, false)
|
||||
binding.homeLoadingError
|
||||
|
||||
val binding2 = FragmentHomeBinding.inflate(layout, container, false)
|
||||
binding2.homeLoadingError*/
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
binding = FragmentHomeBinding.bind(root)
|
||||
//val localBinding = FragmentHomeBinding.inflate(inflater)
|
||||
//binding = localBinding
|
||||
return root
|
||||
|
||||
//return inflater.inflate(layout, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetDialog?.ownHide()
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
@ -467,7 +481,7 @@ class HomeFragment : Fragment() {
|
|||
fixGrid()
|
||||
}
|
||||
|
||||
fun bookmarksUpdated(_data : Boolean) {
|
||||
fun bookmarksUpdated(_data: Boolean) {
|
||||
reloadStored()
|
||||
}
|
||||
|
||||
|
@ -525,14 +539,18 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private var bottomSheetDialog: BottomSheetDialog? = null
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
fixGrid()
|
||||
|
||||
home_change_api_loading?.setOnClickListener(apiChangeClickListener)
|
||||
home_api_fab?.setOnClickListener(apiChangeClickListener)
|
||||
home_random?.setOnClickListener {
|
||||
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
|
||||
|
||||
|
||||
binding?.homeChangeApiLoading?.setOnClickListener(apiChangeClickListener)
|
||||
binding?.homeApiFab?.setOnClickListener(apiChangeClickListener)
|
||||
binding?.homeRandom?.setOnClickListener {
|
||||
if (listHomepageItems.isNotEmpty()) {
|
||||
activity.loadSearchResult(listHomepageItems.random())
|
||||
}
|
||||
|
@ -542,91 +560,100 @@ class HomeFragment : Fragment() {
|
|||
context?.let {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
||||
toggleRandomButton =
|
||||
settingsManager.getBoolean(getString(R.string.random_button_key), false)
|
||||
home_random?.visibility = View.GONE
|
||||
settingsManager.getBoolean(
|
||||
getString(R.string.random_button_key),
|
||||
false
|
||||
) && !isTvSettings()
|
||||
binding?.homeRandom?.visibility = View.GONE
|
||||
}
|
||||
|
||||
observe(homeViewModel.preview) { preview ->
|
||||
(home_master_recycler?.adapter as? HomeParentItemAdapterPreview?)?.setPreviewData(
|
||||
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setPreviewData(
|
||||
preview
|
||||
)
|
||||
}
|
||||
|
||||
observe(homeViewModel.apiName) { apiName ->
|
||||
currentApiName = apiName
|
||||
home_api_fab?.text = apiName
|
||||
(home_master_recycler?.adapter as? HomeParentItemAdapterPreview?)?.setApiName(
|
||||
binding?.homeApiFab?.text = apiName
|
||||
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setApiName(
|
||||
apiName
|
||||
)
|
||||
}
|
||||
|
||||
observe(homeViewModel.page) { data ->
|
||||
when (data) {
|
||||
is Resource.Success -> {
|
||||
home_loading_shimmer?.stopShimmer()
|
||||
binding?.apply {
|
||||
when (data) {
|
||||
is Resource.Success -> {
|
||||
homeLoadingShimmer.stopShimmer()
|
||||
|
||||
val d = data.value
|
||||
val mutableListOfResponse = mutableListOf<SearchResponse>()
|
||||
listHomepageItems.clear()
|
||||
val d = data.value
|
||||
val mutableListOfResponse = mutableListOf<SearchResponse>()
|
||||
listHomepageItems.clear()
|
||||
|
||||
(home_master_recycler?.adapter as? ParentItemAdapter)?.updateList(
|
||||
d.values.toMutableList(),
|
||||
home_master_recycler
|
||||
)
|
||||
(homeMasterRecycler.adapter as? ParentItemAdapter)?.updateList(
|
||||
d.values.toMutableList(),
|
||||
homeMasterRecycler
|
||||
)
|
||||
|
||||
home_loading?.isVisible = false
|
||||
home_loading_error?.isVisible = false
|
||||
home_master_recycler?.isVisible = true
|
||||
//home_loaded?.isVisible = true
|
||||
if (toggleRandomButton) {
|
||||
//Flatten list
|
||||
d.values.forEach { dlist ->
|
||||
mutableListOfResponse.addAll(dlist.list.list)
|
||||
homeLoading.isVisible = false
|
||||
homeLoadingError.isVisible = false
|
||||
homeMasterRecycler.isVisible = true
|
||||
//home_loaded?.isVisible = true
|
||||
if (toggleRandomButton) {
|
||||
//Flatten list
|
||||
d.values.forEach { dlist ->
|
||||
mutableListOfResponse.addAll(dlist.list.list)
|
||||
}
|
||||
listHomepageItems.addAll(mutableListOfResponse.distinctBy { it.url })
|
||||
|
||||
homeRandom.isVisible = listHomepageItems.isNotEmpty()
|
||||
} else {
|
||||
homeRandom.isGone = true
|
||||
}
|
||||
listHomepageItems.addAll(mutableListOfResponse.distinctBy { it.url })
|
||||
home_random?.isVisible = listHomepageItems.isNotEmpty()
|
||||
} else {
|
||||
home_random?.isGone = true
|
||||
}
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
home_loading_shimmer?.stopShimmer()
|
||||
|
||||
result_error_text.text = data.errorString
|
||||
is Resource.Failure -> {
|
||||
|
||||
home_reload_connectionerror.setOnClickListener(apiChangeClickListener)
|
||||
homeLoadingShimmer.stopShimmer()
|
||||
|
||||
home_reload_connection_open_in_browser.setOnClickListener { view ->
|
||||
val validAPIs = apis//.filter { api -> api.hasMainPage }
|
||||
resultErrorText.text = data.errorString
|
||||
|
||||
view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api ->
|
||||
Pair(
|
||||
index,
|
||||
api.name
|
||||
)
|
||||
}) {
|
||||
try {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.data = Uri.parse(validAPIs[itemId].mainUrl)
|
||||
startActivity(i)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
homeReloadConnectionerror.setOnClickListener(apiChangeClickListener)
|
||||
|
||||
homeReloadConnectionOpenInBrowser.setOnClickListener { view ->
|
||||
val validAPIs = apis//.filter { api -> api.hasMainPage }
|
||||
|
||||
view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api ->
|
||||
Pair(
|
||||
index,
|
||||
api.name
|
||||
)
|
||||
}) {
|
||||
try {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.data = Uri.parse(validAPIs[itemId].mainUrl)
|
||||
startActivity(i)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
homeLoading.isVisible = false
|
||||
homeLoadingError.isVisible = true
|
||||
homeMasterRecycler.isVisible = false
|
||||
//home_loaded?.isVisible = false
|
||||
}
|
||||
|
||||
home_loading?.isVisible = false
|
||||
home_loading_error?.isVisible = true
|
||||
home_master_recycler?.isVisible = false
|
||||
//home_loaded?.isVisible = false
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
(home_master_recycler?.adapter as? ParentItemAdapter)?.updateList(listOf())
|
||||
home_loading_shimmer?.startShimmer()
|
||||
home_loading?.isVisible = true
|
||||
home_loading_error?.isVisible = false
|
||||
home_master_recycler?.isVisible = false
|
||||
//home_loaded?.isVisible = false
|
||||
is Resource.Loading -> {
|
||||
(homeMasterRecycler.adapter as? ParentItemAdapter)?.updateList(listOf())
|
||||
homeLoadingShimmer.startShimmer()
|
||||
homeLoading.isVisible = true
|
||||
homeLoadingError.isVisible = false
|
||||
homeMasterRecycler.isVisible = false
|
||||
//home_loaded?.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -638,19 +665,19 @@ class HomeFragment : Fragment() {
|
|||
HOME_BOOKMARK_VALUE_LIST,
|
||||
availableWatchStatusTypes.first.map { it.internalId }.toIntArray()
|
||||
)
|
||||
(home_master_recycler?.adapter as? HomeParentItemAdapterPreview?)?.setAvailableWatchStatusTypes(
|
||||
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setAvailableWatchStatusTypes(
|
||||
availableWatchStatusTypes
|
||||
)
|
||||
}
|
||||
|
||||
observe(homeViewModel.bookmarks) { data ->
|
||||
(home_master_recycler?.adapter as? HomeParentItemAdapterPreview?)?.setBookmarkData(
|
||||
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setBookmarkData(
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
observe(homeViewModel.resumeWatching) { resumeWatching ->
|
||||
(home_master_recycler?.adapter as? HomeParentItemAdapterPreview?)?.setResumeWatchingData(
|
||||
(binding?.homeMasterRecycler?.adapter as? HomeParentItemAdapterPreview?)?.setResumeWatchingData(
|
||||
resumeWatching
|
||||
)
|
||||
if (isTrueTvSettings()) {
|
||||
|
@ -665,9 +692,9 @@ class HomeFragment : Fragment() {
|
|||
|
||||
//context?.fixPaddingStatusbarView(home_statusbar)
|
||||
//context?.fixPaddingStatusbar(home_padding)
|
||||
context?.fixPaddingStatusbar(home_loading_statusbar)
|
||||
fixPaddingStatusbar(binding?.homeLoadingStatusbar)
|
||||
|
||||
home_master_recycler?.adapter =
|
||||
binding?.homeMasterRecycler?.adapter =
|
||||
HomeParentItemAdapterPreview(mutableListOf(), { callback ->
|
||||
homeHandleSearch(callback)
|
||||
}, { item ->
|
||||
|
@ -699,18 +726,22 @@ class HomeFragment : Fragment() {
|
|||
|
||||
reloadStored()
|
||||
loadHomePage(false)
|
||||
home_master_recycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
binding?.homeMasterRecycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (dy > 0) { //check for scroll down
|
||||
home_api_fab?.shrink() // hide
|
||||
home_random?.shrink()
|
||||
} else if (dy < -5) {
|
||||
if (!isTvSettings()) {
|
||||
home_api_fab?.extend() // show
|
||||
home_random?.extend()
|
||||
|
||||
binding?.apply {
|
||||
if (dy > 0) { //check for scroll down
|
||||
homeApiFab.shrink() // hide
|
||||
homeRandom.shrink()
|
||||
} else if (dy < -5) {
|
||||
if (!isTvSettings()) {
|
||||
homeApiFab.extend() // show
|
||||
homeRandom.extend()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
}
|
||||
})
|
||||
|
@ -718,18 +749,20 @@ class HomeFragment : Fragment() {
|
|||
// nice profile pic on homepage
|
||||
//home_profile_picture_holder?.isVisible = false
|
||||
// just in case
|
||||
if (isTvSettings()) {
|
||||
home_api_fab?.isVisible = false
|
||||
if (isTrueTvSettings()) {
|
||||
home_change_api_loading?.isVisible = true
|
||||
home_change_api_loading?.isFocusable = true
|
||||
home_change_api_loading?.isFocusableInTouchMode = true
|
||||
binding?.apply {
|
||||
if (isTvSettings()) {
|
||||
homeApiFab.isVisible = false
|
||||
if (isTrueTvSettings()) {
|
||||
homeChangeApiLoading.isVisible = true
|
||||
homeChangeApiLoading.isFocusable = true
|
||||
homeChangeApiLoading.isFocusableInTouchMode = true
|
||||
}
|
||||
// home_bookmark_select?.isFocusable = true
|
||||
// home_bookmark_select?.isFocusableInTouchMode = true
|
||||
} else {
|
||||
homeApiFab.isVisible = true
|
||||
homeChangeApiLoading.isVisible = false
|
||||
}
|
||||
// home_bookmark_select?.isFocusable = true
|
||||
// home_bookmark_select?.isFocusableInTouchMode = true
|
||||
} else {
|
||||
home_api_fab?.isVisible = true
|
||||
home_change_api_loading?.isVisible = false
|
||||
}
|
||||
//TODO READD THIS
|
||||
/*for (syncApi in OAuth2Apis) {
|
||||
|
|
|
@ -544,7 +544,7 @@ class HomeParentItemAdapterPreview(
|
|||
}
|
||||
}
|
||||
|
||||
itemView.home_search?.context?.fixPaddingStatusbar(itemView.home_search)
|
||||
fixPaddingStatusbar(itemView.home_search)
|
||||
|
||||
itemView.home_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
|
@ -575,7 +575,7 @@ class HomeParentItemAdapterPreview(
|
|||
layoutParams = params
|
||||
}
|
||||
} else {
|
||||
itemView.home_none_padding?.context?.fixPaddingStatusbarView(itemView.home_none_padding)
|
||||
fixPaddingStatusbarView(itemView.home_none_padding)
|
||||
}
|
||||
when (preview) {
|
||||
is Resource.Success -> {
|
||||
|
|
|
@ -6,7 +6,6 @@ import android.content.res.Configuration
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -14,6 +13,7 @@ import android.view.animation.AlphaAnimation
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.lagradost.cloudstream3.APIHolder
|
||||
|
@ -22,6 +22,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
|||
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
|
@ -37,7 +38,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.reduceDragSensitivity
|
|||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
import kotlin.math.abs
|
||||
|
||||
const val LIBRARY_FOLDER = "library_folder"
|
||||
|
@ -73,14 +73,25 @@ class LibraryFragment : Fragment() {
|
|||
|
||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||
|
||||
var binding: FragmentLibraryBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_library, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentLibraryBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
|
||||
//return inflater.inflate(R.layout.fragment_library, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
viewpager?.currentItem?.let { currentItem ->
|
||||
binding?.viewpager?.currentItem?.let { currentItem ->
|
||||
outState.putInt(VIEWPAGER_ITEM_KEY, currentItem)
|
||||
}
|
||||
super.onSaveInstanceState(outState)
|
||||
|
@ -88,9 +99,9 @@ class LibraryFragment : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(search_status_bar_padding)
|
||||
fixPaddingStatusbar(binding?.searchStatusBarPadding)
|
||||
|
||||
sort_fab?.setOnClickListener {
|
||||
binding?.sortFab?.setOnClickListener {
|
||||
val methods = libraryViewModel.sortingMethods.map {
|
||||
txt(it.stringRes).asString(view.context)
|
||||
}
|
||||
|
@ -106,7 +117,7 @@ class LibraryFragment : Fragment() {
|
|||
})
|
||||
}
|
||||
|
||||
main_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
binding?.mainSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
libraryViewModel.sort(ListSorting.Query, query)
|
||||
return true
|
||||
|
@ -129,7 +140,7 @@ class LibraryFragment : Fragment() {
|
|||
|
||||
libraryViewModel.reloadPages(false)
|
||||
|
||||
list_selector?.setOnClickListener {
|
||||
binding?.listSelector?.setOnClickListener {
|
||||
val items = libraryViewModel.availableApiNames
|
||||
val currentItem = libraryViewModel.currentApiName.value
|
||||
|
||||
|
@ -209,20 +220,22 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
provider_selector?.setOnClickListener {
|
||||
binding?.providerSelector?.setOnClickListener {
|
||||
val syncName = libraryViewModel.currentSyncApi?.syncIdName ?: return@setOnClickListener
|
||||
activity?.showPluginSelectionDialog(syncName.name, syncName)
|
||||
}
|
||||
|
||||
viewpager?.setPageTransformer(LibraryScrollTransformer())
|
||||
viewpager?.adapter =
|
||||
viewpager.adapter ?: ViewpagerAdapter(mutableListOf(), { isScrollingDown: Boolean ->
|
||||
if (isScrollingDown) {
|
||||
sort_fab?.shrink()
|
||||
} else {
|
||||
sort_fab?.extend()
|
||||
}
|
||||
}) callback@{ searchClickCallback ->
|
||||
binding?.viewpager?.setPageTransformer(LibraryScrollTransformer())
|
||||
binding?.viewpager?.adapter =
|
||||
binding?.viewpager?.adapter ?: ViewpagerAdapter(
|
||||
mutableListOf(),
|
||||
{ isScrollingDown: Boolean ->
|
||||
if (isScrollingDown) {
|
||||
binding?.sortFab?.shrink()
|
||||
} else {
|
||||
binding?.sortFab?.extend()
|
||||
}
|
||||
}) callback@{ searchClickCallback ->
|
||||
// To prevent future accidents
|
||||
debugAssert({
|
||||
searchClickCallback.card !is SyncAPI.LibraryItem
|
||||
|
@ -267,6 +280,7 @@ class LibraryFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
LibraryOpenerType.None -> {}
|
||||
LibraryOpenerType.Provider ->
|
||||
savedSelection.providerData?.apiName?.let { apiName ->
|
||||
|
@ -275,8 +289,10 @@ class LibraryFragment : Fragment() {
|
|||
apiName,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryOpenerType.Browser ->
|
||||
openBrowser(searchClickCallback.card.url)
|
||||
|
||||
LibraryOpenerType.Search -> {
|
||||
QuickSearchFragment.pushSearch(
|
||||
activity,
|
||||
|
@ -288,22 +304,28 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
viewpager?.offscreenPageLimit = 2
|
||||
viewpager?.reduceDragSensitivity()
|
||||
binding?.apply {
|
||||
viewpager.offscreenPageLimit = 2
|
||||
viewpager.reduceDragSensitivity()
|
||||
}
|
||||
|
||||
val startLoading = Runnable {
|
||||
gridview?.numColumns = context?.getSpanCount() ?: 3
|
||||
gridview?.adapter =
|
||||
context?.let { LoadingPosterAdapter(it, 6 * 3) }
|
||||
library_loading_overlay?.isVisible = true
|
||||
library_loading_shimmer?.startShimmer()
|
||||
empty_list_textview?.isVisible = false
|
||||
binding?.apply {
|
||||
gridview.numColumns = context?.getSpanCount() ?: 3
|
||||
gridview.adapter =
|
||||
context?.let { LoadingPosterAdapter(it, 6 * 3) }
|
||||
libraryLoadingOverlay.isVisible = true
|
||||
libraryLoadingShimmer.startShimmer()
|
||||
emptyListTextview.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
val stopLoading = Runnable {
|
||||
gridview?.adapter = null
|
||||
library_loading_overlay?.isVisible = false
|
||||
library_loading_shimmer?.stopShimmer()
|
||||
binding?.apply {
|
||||
gridview.adapter = null
|
||||
libraryLoadingOverlay.isVisible = false
|
||||
libraryLoadingShimmer.stopShimmer()
|
||||
}
|
||||
}
|
||||
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
@ -314,65 +336,75 @@ class LibraryFragment : Fragment() {
|
|||
handler.removeCallbacks(startLoading)
|
||||
val pages = resource.value
|
||||
val showNotice = pages.all { it.items.isEmpty() }
|
||||
empty_list_textview?.isVisible = showNotice
|
||||
if (showNotice) {
|
||||
if (libraryViewModel.availableApiNames.size > 1) {
|
||||
empty_list_textview?.setText(R.string.empty_library_logged_in_message)
|
||||
} else {
|
||||
empty_list_textview?.setText(R.string.empty_library_no_accounts_message)
|
||||
|
||||
|
||||
binding?.apply {
|
||||
emptyListTextview.isVisible = showNotice
|
||||
if (showNotice) {
|
||||
if (libraryViewModel.availableApiNames.size > 1) {
|
||||
emptyListTextview.setText(R.string.empty_library_logged_in_message)
|
||||
} else {
|
||||
emptyListTextview.setText(R.string.empty_library_no_accounts_message)
|
||||
}
|
||||
}
|
||||
|
||||
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages
|
||||
// Using notifyItemRangeChanged keeps the animations when sorting
|
||||
viewpager.adapter?.notifyItemRangeChanged(
|
||||
0,
|
||||
viewpager.adapter?.itemCount ?: 0
|
||||
)
|
||||
|
||||
// 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
|
||||
handler.postDelayed(stopLoading, 300)
|
||||
|
||||
savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->
|
||||
if (currentPos < 0) return@let
|
||||
viewpager.setCurrentItem(currentPos, false)
|
||||
// Using remove() sets the key to 0 instead of removing it
|
||||
savedInstanceState.putInt(VIEWPAGER_ITEM_KEY, -1)
|
||||
}
|
||||
|
||||
// Since the animation to scroll multiple items is so much its better to just hide
|
||||
// the viewpager a bit while the fastest animation is running
|
||||
fun hideViewpager(distance: Int) {
|
||||
if (distance < 3) return
|
||||
|
||||
val hideAnimation = AlphaAnimation(1f, 0f).apply {
|
||||
duration = distance * 50L
|
||||
fillAfter = true
|
||||
}
|
||||
val showAnimation = AlphaAnimation(0f, 1f).apply {
|
||||
duration = distance * 50L
|
||||
startOffset = distance * 100L
|
||||
fillAfter = true
|
||||
}
|
||||
viewpager.startAnimation(hideAnimation)
|
||||
viewpager.startAnimation(showAnimation)
|
||||
}
|
||||
|
||||
TabLayoutMediator(
|
||||
libraryTabLayout,
|
||||
viewpager,
|
||||
) { tab, position ->
|
||||
tab.text = pages.getOrNull(position)?.title?.asStringNull(context)
|
||||
tab.view.setOnClickListener {
|
||||
val currentItem =
|
||||
binding?.viewpager?.currentItem ?: return@setOnClickListener
|
||||
val distance = abs(position - currentItem)
|
||||
hideViewpager(distance)
|
||||
}
|
||||
}.attach()
|
||||
}
|
||||
|
||||
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages
|
||||
// Using notifyItemRangeChanged keeps the animations when sorting
|
||||
viewpager.adapter?.notifyItemRangeChanged(0, viewpager.adapter?.itemCount ?: 0)
|
||||
|
||||
// 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
|
||||
handler.postDelayed(stopLoading, 300)
|
||||
|
||||
savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->
|
||||
if (currentPos < 0) return@let
|
||||
viewpager?.setCurrentItem(currentPos, false)
|
||||
// Using remove() sets the key to 0 instead of removing it
|
||||
savedInstanceState.putInt(VIEWPAGER_ITEM_KEY, -1)
|
||||
}
|
||||
|
||||
// Since the animation to scroll multiple items is so much its better to just hide
|
||||
// the viewpager a bit while the fastest animation is running
|
||||
fun hideViewpager(distance: Int) {
|
||||
if (distance < 3) return
|
||||
|
||||
val hideAnimation = AlphaAnimation(1f, 0f).apply {
|
||||
duration = distance * 50L
|
||||
fillAfter = true
|
||||
}
|
||||
val showAnimation = AlphaAnimation(0f, 1f).apply {
|
||||
duration = distance * 50L
|
||||
startOffset = distance * 100L
|
||||
fillAfter = true
|
||||
}
|
||||
viewpager?.startAnimation(hideAnimation)
|
||||
viewpager?.startAnimation(showAnimation)
|
||||
}
|
||||
|
||||
TabLayoutMediator(
|
||||
library_tab_layout,
|
||||
viewpager,
|
||||
) { tab, position ->
|
||||
tab.text = pages.getOrNull(position)?.title?.asStringNull(context)
|
||||
tab.view.setOnClickListener {
|
||||
val currentItem = viewpager?.currentItem ?: return@setOnClickListener
|
||||
val distance = abs(position - currentItem)
|
||||
hideViewpager(distance)
|
||||
}
|
||||
}.attach()
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
// Only start loading after 200ms to prevent loading cached lists
|
||||
handler.postDelayed(startLoading, 200)
|
||||
}
|
||||
|
||||
is Resource.Failure -> {
|
||||
stopLoading.run()
|
||||
// No user indication it failed :(
|
||||
|
@ -383,7 +415,7 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
(viewpager.adapter as? ViewpagerAdapter)?.rebind()
|
||||
(binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind()
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.lagradost.cloudstream3.mvvm.Resource
|
|||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.SyncApis
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
enum class ListSorting(@StringRes val stringRes: Int) {
|
||||
Query(R.string.none),
|
||||
|
|
|
@ -3,23 +3,21 @@ package com.lagradost.cloudstream3.ui.library
|
|||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.AcraApplication
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
import kotlinx.android.synthetic.main.search_result_grid_expanded.view.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
|
@ -32,8 +30,7 @@ class PageAdapter(
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return LibraryItemViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.search_result_grid_expanded, parent, false)
|
||||
SearchResultGridExpandedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -57,8 +54,7 @@ class PageAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
inner class LibraryItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: ImageView = itemView.imageView
|
||||
inner class LibraryItemViewHolder(val binding : SearchResultGridExpandedBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private val compactView = false//itemView.context.getGridIsCompact()
|
||||
private val coverHeight: Int =
|
||||
|
@ -85,11 +81,11 @@ class PageAdapter(
|
|||
|
||||
val fg =
|
||||
getDifferentColor(bg)//palette.getVibrantColor(ContextCompat.getColor(ctx,R.color.ratingColor))
|
||||
itemView.text_rating.apply {
|
||||
binding.textRating.apply {
|
||||
setTextColor(ColorStateList.valueOf(fg))
|
||||
}
|
||||
itemView.text_rating_holder?.backgroundTintList = ColorStateList.valueOf(bg)
|
||||
itemView.watchProgress?.apply {
|
||||
binding.textRatingHolder.backgroundTintList = ColorStateList.valueOf(bg)
|
||||
binding.watchProgress.apply {
|
||||
progressTintList = ColorStateList.valueOf(fg)
|
||||
progressBackgroundTintList = ColorStateList.valueOf(bg)
|
||||
}
|
||||
|
@ -99,7 +95,7 @@ class PageAdapter(
|
|||
|
||||
// See searchAdaptor for this, it basically fixes the height
|
||||
if (!compactView) {
|
||||
cardView.apply {
|
||||
binding.imageView.apply {
|
||||
layoutParams = FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
coverHeight
|
||||
|
@ -108,22 +104,22 @@ class PageAdapter(
|
|||
}
|
||||
|
||||
val showProgress = item.episodesCompleted != null && item.episodesTotal != null
|
||||
itemView.watchProgress.isVisible = showProgress
|
||||
binding.watchProgress.isVisible = showProgress
|
||||
if (showProgress) {
|
||||
itemView.watchProgress.max = item.episodesTotal!!
|
||||
itemView.watchProgress.progress = item.episodesCompleted!!
|
||||
binding.watchProgress.max = item.episodesTotal!!
|
||||
binding.watchProgress.progress = item.episodesCompleted!!
|
||||
}
|
||||
|
||||
itemView.imageText.text = item.name
|
||||
binding.imageText.text = item.name
|
||||
|
||||
val showRating = (item.personalRating ?: 0) != 0
|
||||
itemView.text_rating_holder.isVisible = showRating
|
||||
binding.textRatingHolder.isVisible = showRating
|
||||
if (showRating) {
|
||||
// We want to show 8.5 but not 8.0 hence the replace
|
||||
val rating = ((item.personalRating ?: 0).toDouble() / 10).toString()
|
||||
.replace(".0", "")
|
||||
|
||||
itemView.text_rating.text = "★ $rating"
|
||||
binding.textRating.text = "★ $rating"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,14 @@ package com.lagradost.cloudstream3.ui.library
|
|||
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.doOnAttach
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnFlingListener
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.LibraryViewpagerPageBinding
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import kotlinx.android.synthetic.main.library_viewpager_page.view.*
|
||||
|
||||
class ViewpagerAdapter(
|
||||
var pages: List<SyncAPI.Page>,
|
||||
|
@ -20,8 +18,7 @@ class ViewpagerAdapter(
|
|||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return PageViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.library_viewpager_page, parent, false)
|
||||
LibraryViewpagerPageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -34,6 +31,7 @@ class ViewpagerAdapter(
|
|||
}
|
||||
|
||||
private val unbound = mutableSetOf<Int>()
|
||||
|
||||
/**
|
||||
* Used to mark all pages for re-binding and forces all items to be refreshed
|
||||
* Without this the pages will still use the same adapters
|
||||
|
@ -43,44 +41,46 @@ class ViewpagerAdapter(
|
|||
this.notifyItemRangeChanged(0, pages.size)
|
||||
}
|
||||
|
||||
inner class PageViewHolder(private val itemViewTest: View) :
|
||||
RecyclerView.ViewHolder(itemViewTest) {
|
||||
inner class PageViewHolder(private val binding: LibraryViewpagerPageBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(page: SyncAPI.Page, rebind: Boolean) {
|
||||
itemView.page_recyclerview?.spanCount =
|
||||
this@PageViewHolder.itemView.context.getSpanCount() ?: 3
|
||||
|
||||
if (itemViewTest.page_recyclerview?.adapter == null || rebind) {
|
||||
// Only add the items after it has been attached since the items rely on ItemWidth
|
||||
// Which is only determined after the recyclerview is attached.
|
||||
// If this fails then item height becomes 0 when there is only one item
|
||||
itemViewTest.page_recyclerview?.doOnAttach {
|
||||
itemViewTest.page_recyclerview?.adapter = PageAdapter(
|
||||
page.items.toMutableList(),
|
||||
itemViewTest.page_recyclerview,
|
||||
clickCallback
|
||||
)
|
||||
binding.pageRecyclerview.apply {
|
||||
spanCount =
|
||||
this@PageViewHolder.itemView.context.getSpanCount() ?: 3
|
||||
if (adapter == null || rebind) {
|
||||
// Only add the items after it has been attached since the items rely on ItemWidth
|
||||
// Which is only determined after the recyclerview is attached.
|
||||
// If this fails then item height becomes 0 when there is only one item
|
||||
doOnAttach {
|
||||
adapter = PageAdapter(
|
||||
page.items.toMutableList(),
|
||||
this,
|
||||
clickCallback
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(adapter as? PageAdapter)?.updateList(page.items)
|
||||
scrollToPosition(0)
|
||||
}
|
||||
} else {
|
||||
(itemViewTest.page_recyclerview?.adapter as? PageAdapter)?.updateList(page.items)
|
||||
itemViewTest.page_recyclerview?.scrollToPosition(0)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
itemViewTest.page_recyclerview.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
||||
val diff = scrollY - oldScrollY
|
||||
if (diff == 0) return@setOnScrollChangeListener
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
||||
val diff = scrollY - oldScrollY
|
||||
if (diff == 0) return@setOnScrollChangeListener
|
||||
|
||||
scrollCallback.invoke(diff > 0)
|
||||
}
|
||||
} else {
|
||||
itemViewTest.page_recyclerview.onFlingListener = object : OnFlingListener() {
|
||||
override fun onFling(velocityX: Int, velocityY: Int): Boolean {
|
||||
scrollCallback.invoke(velocityY > 0)
|
||||
return false
|
||||
scrollCallback.invoke(diff > 0)
|
||||
}
|
||||
} else {
|
||||
onFlingListener = object : OnFlingListener() {
|
||||
override fun onFling(velocityX: Int, velocityY: Int): Boolean {
|
||||
scrollCallback.invoke(velocityY > 0)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.APIHolder.filterSearchResultByFilmQuality
|
|||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
import com.lagradost.cloudstream3.HomePageList
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.QuickSearchBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
|
@ -37,7 +38,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||
import kotlinx.android.synthetic.main.quick_search.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
class QuickSearchFragment : Fragment() {
|
||||
|
@ -72,6 +72,8 @@ class QuickSearchFragment : Fragment() {
|
|||
|
||||
private var providers: Set<String>? = null
|
||||
private lateinit var searchViewModel: SearchViewModel
|
||||
var binding: QuickSearchBinding? = null
|
||||
|
||||
|
||||
private var bottomSheetDialog: BottomSheetDialog? = null
|
||||
|
||||
|
@ -79,13 +81,21 @@ class QuickSearchFragment : Fragment() {
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
): View {
|
||||
activity?.window?.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
|
||||
)
|
||||
searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]
|
||||
bottomSheetDialog?.ownShow()
|
||||
return inflater.inflate(R.layout.quick_search, container, false)
|
||||
val localBinding = QuickSearchBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.quick_search, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -111,7 +121,7 @@ class QuickSearchFragment : Fragment() {
|
|||
activity?.getSpanCount()?.let {
|
||||
HomeFragment.currentSpan = it
|
||||
}
|
||||
quick_search_autofit_results.spanCount = HomeFragment.currentSpan
|
||||
binding?.quickSearchAutofitResults?.spanCount = HomeFragment.currentSpan
|
||||
HomeFragment.currentSpan = HomeFragment.currentSpan
|
||||
HomeFragment.configEvent.invoke(HomeFragment.currentSpan)
|
||||
}
|
||||
|
@ -123,7 +133,7 @@ class QuickSearchFragment : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(quick_search_root)
|
||||
fixPaddingStatusbar(binding?.quickSearchRoot)
|
||||
fixGrid()
|
||||
|
||||
arguments?.getStringArray(PROVIDER_KEY)?.let {
|
||||
|
@ -136,21 +146,22 @@ class QuickSearchFragment : Fragment() {
|
|||
} else false
|
||||
|
||||
if (isSingleProvider) {
|
||||
quick_search_autofit_results.adapter = activity?.let {
|
||||
SearchAdapter(
|
||||
binding?.quickSearchAutofitResults?.apply {
|
||||
adapter = SearchAdapter(
|
||||
ArrayList(),
|
||||
quick_search_autofit_results,
|
||||
this,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
quick_search?.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) {
|
||||
logError(e)
|
||||
}
|
||||
} else {
|
||||
quick_search_master_recycler?.adapter =
|
||||
binding?.quickSearchMasterRecycler?.adapter =
|
||||
ParentItemAdapter(mutableListOf(), { callback ->
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
//when (callback.action) {
|
||||
|
@ -164,18 +175,17 @@ class QuickSearchFragment : Fragment() {
|
|||
bottomSheetDialog = null
|
||||
})
|
||||
})
|
||||
quick_search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
|
||||
binding?.quickSearchMasterRecycler?.layoutManager = GridLayoutManager(context, 1)
|
||||
}
|
||||
|
||||
quick_search_autofit_results?.isVisible = isSingleProvider
|
||||
quick_search_master_recycler?.isGone = isSingleProvider
|
||||
binding?.quickSearchAutofitResults?.isVisible = isSingleProvider
|
||||
binding?.quickSearchMasterRecycler?.isGone = isSingleProvider
|
||||
|
||||
val listLock = ReentrantLock()
|
||||
observe(searchViewModel.currentSearch) { list ->
|
||||
try {
|
||||
// https://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist
|
||||
listLock.lock()
|
||||
(quick_search_master_recycler?.adapter as ParentItemAdapter?)?.apply {
|
||||
(binding?.quickSearchMasterRecycler?.adapter as ParentItemAdapter?)?.apply {
|
||||
updateList(list.map { ongoing ->
|
||||
val ongoingList = HomePageList(
|
||||
ongoing.apiName,
|
||||
|
@ -192,19 +202,18 @@ class QuickSearchFragment : Fragment() {
|
|||
}
|
||||
|
||||
val searchExitIcon =
|
||||
quick_search?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||
binding?.quickSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||
|
||||
//val searchMagIcon =
|
||||
// quick_search?.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
||||
// binding.quickSearch.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
||||
|
||||
//searchMagIcon?.scaleX = 0.65f
|
||||
//searchMagIcon?.scaleY = 0.65f
|
||||
|
||||
|
||||
quick_search?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
binding?.quickSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
if (search(context, query, false))
|
||||
UIHelper.hideKeyboard(quick_search)
|
||||
UIHelper.hideKeyboard(binding?.quickSearch)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -214,27 +223,26 @@ class QuickSearchFragment : Fragment() {
|
|||
return true
|
||||
}
|
||||
})
|
||||
|
||||
quick_search_loading_bar.alpha = 0f
|
||||
binding?.quickSearchLoadingBar?.alpha = 0f
|
||||
observe(searchViewModel.searchResponse) {
|
||||
when (it) {
|
||||
is Resource.Success -> {
|
||||
it.value.let { data ->
|
||||
(quick_search_autofit_results?.adapter as? SearchAdapter)?.updateList(
|
||||
(binding?.quickSearchAutofitResults?.adapter as? SearchAdapter)?.updateList(
|
||||
context?.filterSearchResultByFilmQuality(data) ?: data
|
||||
)
|
||||
}
|
||||
searchExitIcon?.alpha = 1f
|
||||
quick_search_loading_bar?.alpha = 0f
|
||||
binding?.quickSearchLoadingBar?.alpha = 0f
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
// Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
|
||||
searchExitIcon?.alpha = 1f
|
||||
quick_search_loading_bar?.alpha = 0f
|
||||
binding?.quickSearchLoadingBar?.alpha = 0f
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
searchExitIcon?.alpha = 0f
|
||||
quick_search_loading_bar?.alpha = 1f
|
||||
binding?.quickSearchLoadingBar?.alpha = 1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,13 +254,12 @@ class QuickSearchFragment : Fragment() {
|
|||
// UIHelper.showInputMethod(view.findFocus())
|
||||
// }
|
||||
//}
|
||||
|
||||
quick_search_back.setOnClickListener {
|
||||
binding?.quickSearchBack?.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
arguments?.getString(AUTOSEARCH_KEY)?.let {
|
||||
quick_search?.setQuery(it, true)
|
||||
binding?.quickSearch?.setQuery(it, true)
|
||||
arguments?.remove(AUTOSEARCH_KEY)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.ActorData
|
||||
import com.lagradost.cloudstream3.ActorRole
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.CastItemBinding
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import kotlinx.android.synthetic.main.cast_item.view.*
|
||||
|
||||
class ActorAdaptor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
class ActorAdaptor : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
data class ActorMetaData(
|
||||
var isInverted: Boolean,
|
||||
val actor: ActorData,
|
||||
|
@ -24,7 +21,7 @@ class ActorAdaptor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return CardViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(R.layout.cast_item, parent, false),
|
||||
CastItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -68,15 +65,9 @@ class ActorAdaptor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
|
||||
private class CardViewHolder
|
||||
constructor(
|
||||
itemView: View,
|
||||
val binding: CastItemBinding,
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private val actorImage: ImageView = itemView.actor_image
|
||||
private val actorName: TextView = itemView.actor_name
|
||||
private val actorExtra: TextView = itemView.actor_extra
|
||||
private val voiceActorImage: ImageView = itemView.voice_actor_image
|
||||
private val voiceActorImageHolder: View = itemView.voice_actor_image_holder
|
||||
private val voiceActorName: TextView = itemView.voice_actor_name
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(actor: ActorData, isInverted: Boolean, position: Int, callback: (Int) -> Unit) {
|
||||
val (mainImg, vaImage) = if (!isInverted || actor.voiceActor?.image.isNullOrBlank()) {
|
||||
|
@ -89,39 +80,43 @@ class ActorAdaptor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
callback(position)
|
||||
}
|
||||
|
||||
actorImage.setImage(mainImg)
|
||||
binding.apply {
|
||||
actorImage.setImage(mainImg)
|
||||
|
||||
actorName.text = actor.actor.name
|
||||
actor.role?.let {
|
||||
actorExtra.context?.getString(
|
||||
when (it) {
|
||||
ActorRole.Main -> {
|
||||
R.string.actor_main
|
||||
}
|
||||
ActorRole.Supporting -> {
|
||||
R.string.actor_supporting
|
||||
}
|
||||
ActorRole.Background -> {
|
||||
R.string.actor_background
|
||||
actorName.text = actor.actor.name
|
||||
actor.role?.let {
|
||||
actorExtra.context?.getString(
|
||||
when (it) {
|
||||
ActorRole.Main -> {
|
||||
R.string.actor_main
|
||||
}
|
||||
|
||||
ActorRole.Supporting -> {
|
||||
R.string.actor_supporting
|
||||
}
|
||||
|
||||
ActorRole.Background -> {
|
||||
R.string.actor_background
|
||||
}
|
||||
}
|
||||
)?.let { text ->
|
||||
actorExtra.isVisible = true
|
||||
actorExtra.text = text
|
||||
}
|
||||
)?.let { text ->
|
||||
} ?: actor.roleString?.let {
|
||||
actorExtra.isVisible = true
|
||||
actorExtra.text = text
|
||||
actorExtra.text = it
|
||||
} ?: run {
|
||||
actorExtra.isVisible = false
|
||||
}
|
||||
} ?: actor.roleString?.let {
|
||||
actorExtra.isVisible = true
|
||||
actorExtra.text = it
|
||||
} ?: run {
|
||||
actorExtra.isVisible = false
|
||||
}
|
||||
|
||||
if (actor.voiceActor == null) {
|
||||
voiceActorImageHolder.isVisible = false
|
||||
voiceActorName.isVisible = false
|
||||
} else {
|
||||
voiceActorName.text = actor.voiceActor.name
|
||||
voiceActorImageHolder.isVisible = voiceActorImage.setImage(vaImage)
|
||||
if (actor.voiceActor == null) {
|
||||
voiceActorImageHolder.isVisible = false
|
||||
voiceActorName.isVisible = false
|
||||
} else {
|
||||
voiceActorName.text = actor.voiceActor.name
|
||||
voiceActorImageHolder.isVisible = voiceActorImage.setImage(vaImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,34 +3,25 @@ package com.lagradost.cloudstream3.ui.result
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ContentLoadingProgressBar
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.ResultEpisodeBinding
|
||||
import com.lagradost.cloudstream3.databinding.ResultEpisodeLargeBinding
|
||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
|
||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import kotlinx.android.synthetic.main.result_episode.view.*
|
||||
import kotlinx.android.synthetic.main.result_episode.view.episode_text
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.*
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.episode_filler
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.episode_progress
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_download
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_progress_downloaded
|
||||
import java.util.*
|
||||
|
||||
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
||||
|
@ -144,26 +135,52 @@ class EpisodeAdapter(
|
|||
diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
var layout = R.layout.result_episode_both
|
||||
fun getItem(position: Int) : ResultEpisode {
|
||||
return cardList[position]
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val item = getItem(position)
|
||||
return if(item.poster.isNullOrBlank()) 0 else 1
|
||||
}
|
||||
|
||||
|
||||
// private val layout = R.layout.result_episode_both
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
/*val layout = if (cardList.filter { it.poster != null }.size >= cardList.size / 2)
|
||||
R.layout.result_episode_large
|
||||
else R.layout.result_episode*/
|
||||
|
||||
return EpisodeCardViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(layout, parent, false),
|
||||
hasDownloadSupport,
|
||||
clickCallback,
|
||||
downloadClickCallback
|
||||
)
|
||||
return when(viewType) {
|
||||
0 -> {
|
||||
EpisodeCardViewHolderSmall(
|
||||
ResultEpisodeBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
hasDownloadSupport,
|
||||
clickCallback,
|
||||
downloadClickCallback
|
||||
)
|
||||
}
|
||||
1 -> {
|
||||
EpisodeCardViewHolderLarge(
|
||||
ResultEpisodeLargeBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
hasDownloadSupport,
|
||||
clickCallback,
|
||||
downloadClickCallback
|
||||
)
|
||||
}
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is EpisodeCardViewHolder -> {
|
||||
holder.bind(cardList[position])
|
||||
is EpisodeCardViewHolderLarge -> {
|
||||
holder.bind(getItem(position))
|
||||
mBoundViewHolders.add(holder)
|
||||
}
|
||||
is EpisodeCardViewHolderSmall -> {
|
||||
holder.bind(getItem(position))
|
||||
mBoundViewHolders.add(holder)
|
||||
}
|
||||
}
|
||||
|
@ -173,94 +190,81 @@ class EpisodeAdapter(
|
|||
return cardList.size
|
||||
}
|
||||
|
||||
class EpisodeCardViewHolder
|
||||
class EpisodeCardViewHolderLarge
|
||||
constructor(
|
||||
itemView: View,
|
||||
val binding : ResultEpisodeLargeBinding,
|
||||
private val hasDownloadSupport: Boolean,
|
||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
|
||||
) : RecyclerView.ViewHolder(binding.root), DownloadButtonViewHolder {
|
||||
override var downloadButton = EasyDownloadButton()
|
||||
|
||||
var episodeDownloadBar: ContentLoadingProgressBar? = null
|
||||
var episodeDownloadImage: ImageView? = null
|
||||
// TODO TV
|
||||
|
||||
var localCard: ResultEpisode? = null
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: ResultEpisode) {
|
||||
localCard = card
|
||||
|
||||
binding.episodeLinHolder.layoutParams.apply {
|
||||
width = if(isTvSettings()) ViewGroup.LayoutParams.WRAP_CONTENT else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
|
||||
val (parentView, otherView) = if (card.poster == null) {
|
||||
itemView.episode_holder to itemView.episode_holder_large
|
||||
} else {
|
||||
itemView.episode_holder_large to itemView.episode_holder
|
||||
}
|
||||
parentView.isVisible = true
|
||||
otherView.isVisible = false
|
||||
binding.apply {
|
||||
|
||||
val episodeText: TextView = parentView.episode_text
|
||||
val episodeFiller: MaterialButton? = parentView.episode_filler
|
||||
val episodeRating: TextView? = parentView.episode_rating
|
||||
val episodeDescript: TextView? = parentView.episode_descript
|
||||
val episodeProgress: ContentLoadingProgressBar? = parentView.episode_progress
|
||||
val episodePoster: ImageView? = parentView.episode_poster
|
||||
val name =
|
||||
if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
||||
episodeFiller.isVisible = card.isFiller == true
|
||||
episodeText.text =
|
||||
name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name
|
||||
episodeText.isSelected = true // is needed for text repeating
|
||||
|
||||
episodeDownloadBar =
|
||||
parentView.result_episode_progress_downloaded
|
||||
episodeDownloadImage = parentView.result_episode_download
|
||||
|
||||
val name =
|
||||
if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
||||
episodeFiller?.isVisible = card.isFiller == true
|
||||
episodeText.text =
|
||||
name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name
|
||||
episodeText.isSelected = true // is needed for text repeating
|
||||
|
||||
if (card.videoWatchState == VideoWatchState.Watched) {
|
||||
// This cannot be done in getDisplayPosition() as when you have not watched something
|
||||
// the duration and position is 0
|
||||
episodeProgress?.max = 1
|
||||
episodeProgress?.progress = 1
|
||||
episodeProgress?.isVisible = true
|
||||
} else {
|
||||
val displayPos = card.getDisplayPosition()
|
||||
episodeProgress?.max = (card.duration / 1000).toInt()
|
||||
episodeProgress?.progress = (displayPos / 1000).toInt()
|
||||
episodeProgress?.isVisible = displayPos > 0L
|
||||
}
|
||||
|
||||
episodePoster?.isVisible = episodePoster?.setImage(card.poster) == true
|
||||
|
||||
if (card.rating != null) {
|
||||
episodeRating?.text = episodeRating?.context?.getString(R.string.rated_format)
|
||||
?.format(card.rating.toFloat() / 10f)
|
||||
} else {
|
||||
episodeRating?.text = ""
|
||||
}
|
||||
|
||||
episodeRating?.isGone = episodeRating?.text.isNullOrBlank()
|
||||
|
||||
episodeDescript?.apply {
|
||||
text = card.description.html()
|
||||
isGone = text.isNullOrBlank()
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_DESCRIPTION, card))
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTrueTv) {
|
||||
episodePoster?.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
if (card.videoWatchState == VideoWatchState.Watched) {
|
||||
// This cannot be done in getDisplayPosition() as when you have not watched something
|
||||
// the duration and position is 0
|
||||
episodeProgress.max = 1
|
||||
episodeProgress.progress = 1
|
||||
episodeProgress.isVisible = true
|
||||
} else {
|
||||
val displayPos = card.getDisplayPosition()
|
||||
episodeProgress.max = (card.duration / 1000).toInt()
|
||||
episodeProgress.progress = (displayPos / 1000).toInt()
|
||||
episodeProgress.isVisible = displayPos > 0L
|
||||
}
|
||||
|
||||
episodePoster?.setOnLongClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_TOAST, card))
|
||||
return@setOnLongClickListener true
|
||||
episodePoster.isVisible = episodePoster.setImage(card.poster) == true
|
||||
|
||||
if (card.rating != null) {
|
||||
episodeRating.text = episodeRating.context?.getString(R.string.rated_format)
|
||||
?.format(card.rating.toFloat() / 10f)
|
||||
} else {
|
||||
episodeRating.text = ""
|
||||
}
|
||||
|
||||
episodeRating.isGone = episodeRating.text.isNullOrBlank()
|
||||
|
||||
episodeDescript.apply {
|
||||
text = card.description.html()
|
||||
isGone = text.isNullOrBlank()
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_DESCRIPTION, card))
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTrueTv) {
|
||||
episodePoster.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
episodePoster.setOnLongClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_TOAST, card))
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
@ -276,8 +280,8 @@ class EpisodeAdapter(
|
|||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
episodeDownloadImage?.isVisible = hasDownloadSupport
|
||||
episodeDownloadBar?.isVisible = hasDownloadSupport
|
||||
binding.resultEpisodeDownload.isVisible = hasDownloadSupport
|
||||
binding.resultEpisodeProgressDownloaded.isVisible = hasDownloadSupport
|
||||
reattachDownloadButton()
|
||||
}
|
||||
|
||||
|
@ -285,9 +289,6 @@ class EpisodeAdapter(
|
|||
downloadButton.dispose()
|
||||
val card = localCard
|
||||
if (hasDownloadSupport && card != null) {
|
||||
if (episodeDownloadBar == null ||
|
||||
episodeDownloadImage == null
|
||||
) return
|
||||
val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
itemView.context,
|
||||
card.id
|
||||
|
@ -296,8 +297,109 @@ class EpisodeAdapter(
|
|||
downloadButton.setUpButton(
|
||||
downloadInfo?.fileLength,
|
||||
downloadInfo?.totalBytes,
|
||||
episodeDownloadBar ?: return,
|
||||
episodeDownloadImage ?: return,
|
||||
binding.resultEpisodeProgressDownloaded,
|
||||
binding.resultEpisodeDownload,
|
||||
null,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
card.name,
|
||||
card.poster,
|
||||
card.episode,
|
||||
card.season,
|
||||
card.id,
|
||||
card.parentId,
|
||||
card.rating,
|
||||
card.description,
|
||||
System.currentTimeMillis(),
|
||||
)
|
||||
) {
|
||||
if (it.action == DOWNLOAD_ACTION_DOWNLOAD) {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card))
|
||||
} else {
|
||||
downloadClickCallback.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EpisodeCardViewHolderSmall
|
||||
constructor(
|
||||
val binding : ResultEpisodeBinding,
|
||||
private val hasDownloadSupport: Boolean,
|
||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root), DownloadButtonViewHolder {
|
||||
override var downloadButton = EasyDownloadButton()
|
||||
|
||||
var localCard: ResultEpisode? = null
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: ResultEpisode) {
|
||||
localCard = card
|
||||
|
||||
val isTrueTv = isTrueTvSettings()
|
||||
|
||||
binding.episodeHolder.layoutParams.apply {
|
||||
width = if(isTvSettings()) ViewGroup.LayoutParams.WRAP_CONTENT else ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
|
||||
binding.apply {
|
||||
val name =
|
||||
if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
||||
episodeFiller.isVisible = card.isFiller == true
|
||||
episodeText.text =
|
||||
name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name
|
||||
episodeText.isSelected = true // is needed for text repeating
|
||||
|
||||
if (card.videoWatchState == VideoWatchState.Watched) {
|
||||
// This cannot be done in getDisplayPosition() as when you have not watched something
|
||||
// the duration and position is 0
|
||||
episodeProgress.max = 1
|
||||
episodeProgress.progress = 1
|
||||
episodeProgress.isVisible = true
|
||||
} else {
|
||||
val displayPos = card.getDisplayPosition()
|
||||
episodeProgress.max = (card.duration / 1000).toInt()
|
||||
episodeProgress.progress = (displayPos / 1000).toInt()
|
||||
episodeProgress.isVisible = displayPos > 0L
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
if (isTrueTv) {
|
||||
itemView.isFocusable = true
|
||||
itemView.isFocusableInTouchMode = true
|
||||
//itemView.touchscreenBlocksFocus = false
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
binding.resultEpisodeDownload.isVisible = hasDownloadSupport
|
||||
binding.resultEpisodeProgressDownloaded.isVisible = hasDownloadSupport
|
||||
reattachDownloadButton()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reattachDownloadButton() {
|
||||
downloadButton.dispose()
|
||||
val card = localCard
|
||||
if (hasDownloadSupport && card != null) {
|
||||
|
||||
val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
itemView.context,
|
||||
card.id
|
||||
)
|
||||
|
||||
downloadButton.setUpButton(
|
||||
downloadInfo?.fileLength,
|
||||
downloadInfo?.totalBytes,
|
||||
binding.resultEpisodeProgressDownloaded,
|
||||
binding.resultEpisodeDownload,
|
||||
null,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
card.name,
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.databinding.ResultMiniImageBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
|
||||
/*
|
||||
|
@ -24,7 +23,6 @@ const val IMAGE_CLICK = 0
|
|||
const val IMAGE_LONG_CLICK = 1
|
||||
|
||||
class ImageAdapter(
|
||||
val layout: Int,
|
||||
val clickCallback: ((Int) -> Unit)? = null,
|
||||
val nextFocusUp: Int? = null,
|
||||
val nextFocusDown: Int? = null,
|
||||
|
@ -34,7 +32,9 @@ class ImageAdapter(
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return ImageViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(layout, parent, false)
|
||||
//result_mini_image
|
||||
ResultMiniImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
// LayoutInflater.from(parent.context).inflate(layout, parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -66,15 +66,15 @@ class ImageAdapter(
|
|||
}
|
||||
|
||||
class ImageViewHolder
|
||||
constructor(itemView: View) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
constructor(val binding: ResultMiniImageBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(
|
||||
img: Int,
|
||||
clickCallback: ((Int) -> Unit)?,
|
||||
nextFocusUp: Int?,
|
||||
nextFocusDown: Int?,
|
||||
) {
|
||||
(itemView as? ImageView?)?.apply {
|
||||
binding.root.apply {
|
||||
setImageResource(img)
|
||||
if (nextFocusDown != null) {
|
||||
this.nextFocusDownId = nextFocusDown
|
||||
|
|
|
@ -310,6 +310,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_finish_loading?.isVisible = false
|
||||
result_loading_error?.isVisible = false
|
||||
}
|
||||
|
||||
1 -> {
|
||||
result_bookmark_fab?.isGone = true
|
||||
result_loading?.isVisible = false
|
||||
|
@ -317,6 +318,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_loading_error?.isVisible = true
|
||||
result_reload_connection_open_in_browser?.isVisible = true
|
||||
}
|
||||
|
||||
2 -> {
|
||||
result_bookmark_fab?.isGone = isTrueTvSettings()
|
||||
result_bookmark_fab?.extend()
|
||||
|
@ -350,9 +352,9 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
viewModel.reloadEpisodes()
|
||||
}
|
||||
|
||||
open fun updateMovie(data: ResourceSome<Pair<UiText, ResultEpisode>>) {
|
||||
open fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||
when (data) {
|
||||
is ResourceSome.Success -> {
|
||||
is Resource.Success -> {
|
||||
data.value.let { (text, ep) ->
|
||||
result_play_movie.setText(text)
|
||||
result_play_movie?.setOnClickListener {
|
||||
|
@ -410,6 +412,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, ep)
|
||||
)
|
||||
}
|
||||
|
||||
else -> handleDownloadClick(activity, click)
|
||||
}
|
||||
}
|
||||
|
@ -417,6 +420,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
result_movie_progress_downloaded_holder?.isVisible = false
|
||||
result_play_movie?.isVisible = false
|
||||
|
@ -424,17 +428,14 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
}
|
||||
|
||||
open fun updateEpisodes(episodes: ResourceSome<List<ResultEpisode>>) {
|
||||
open fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||
when (episodes) {
|
||||
is ResourceSome.None -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Loading -> {
|
||||
is Resource.Loading -> {
|
||||
result_episode_loading?.isVisible = true
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Success -> {
|
||||
|
||||
is Resource.Success -> {
|
||||
result_episodes?.isVisible = true
|
||||
result_episode_loading?.isVisible = false
|
||||
|
||||
|
@ -471,6 +472,11 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_episodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,7 +571,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
context?.updateHasTrailers()
|
||||
activity?.loadCache()
|
||||
|
||||
activity?.fixPaddingStatusbar(result_top_bar)
|
||||
fixPaddingStatusbar(result_top_bar)
|
||||
//activity?.fixPaddingStatusbar(result_barstatus)
|
||||
|
||||
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
|
||||
|
@ -588,7 +594,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
|
||||
result_episodes?.adapter =
|
||||
EpisodeAdapter(
|
||||
api?.hasDownloadSupport == true,
|
||||
api?.hasDownloadSupport == true && !isTvSettings(),
|
||||
{ episodeClick ->
|
||||
viewModel.handleAction(activity, episodeClick)
|
||||
},
|
||||
|
@ -738,10 +744,12 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
|
||||
viewModel.setMeta(d, syncModel.getSyncs())
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
result_sync_max_episodes?.text =
|
||||
result_sync_max_episodes?.context?.getString(R.string.sync_total_episodes_none)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
@ -755,11 +763,13 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_sync_holder?.isVisible = false
|
||||
closed = true
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
result_sync_loading_shimmer?.startShimmer()
|
||||
result_sync_loading_shimmer?.isVisible = true
|
||||
result_sync_holder?.isVisible = false
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
result_sync_loading_shimmer?.stopShimmer()
|
||||
result_sync_loading_shimmer?.isVisible = false
|
||||
|
@ -789,6 +799,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
null -> {
|
||||
closed = false
|
||||
}
|
||||
|
@ -796,58 +807,56 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
result_overlapping_panels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)
|
||||
}
|
||||
|
||||
observe(viewModel.resumeWatching) { resume ->
|
||||
when (resume) {
|
||||
is Some.Success -> {
|
||||
result_resume_parent?.isVisible = true
|
||||
val value = resume.value
|
||||
value.progress?.let { progress ->
|
||||
result_resume_series_title?.apply {
|
||||
isVisible = !value.isMovie
|
||||
text =
|
||||
if (value.isMovie) null else activity?.getNameFull(
|
||||
value.result.name,
|
||||
value.result.episode,
|
||||
value.result.season
|
||||
)
|
||||
}
|
||||
result_resume_series_progress_text.setText(progress.progressLeft)
|
||||
result_resume_series_progress?.apply {
|
||||
isVisible = true
|
||||
this.max = progress.maxProgress
|
||||
this.progress = progress.progress
|
||||
}
|
||||
result_resume_progress_holder?.isVisible = true
|
||||
} ?: run {
|
||||
result_resume_progress_holder?.isVisible = false
|
||||
result_resume_series_progress?.isVisible = false
|
||||
result_resume_series_title?.isVisible = false
|
||||
result_resume_series_progress_text?.isVisible = false
|
||||
}
|
||||
|
||||
result_resume_series_button?.isVisible = !value.isMovie
|
||||
result_resume_series_button_play?.isVisible = !value.isMovie
|
||||
|
||||
val click = View.OnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(
|
||||
storedData?.playerAction ?: ACTION_PLAY_EPISODE_IN_PLAYER,
|
||||
value.result
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
result_resume_series_button?.setOnClickListener(click)
|
||||
result_resume_series_button_play?.setOnClickListener(click)
|
||||
}
|
||||
is Some.None -> {
|
||||
result_resume_parent?.isVisible = false
|
||||
}
|
||||
observeNullable(viewModel.resumeWatching) { resume ->
|
||||
if (resume == null) {
|
||||
result_resume_parent?.isVisible = false
|
||||
return@observeNullable
|
||||
}
|
||||
result_resume_parent?.isVisible = true
|
||||
resume.progress?.let { progress ->
|
||||
result_resume_series_title?.apply {
|
||||
isVisible = !resume.isMovie
|
||||
text =
|
||||
if (resume.isMovie) null else activity?.getNameFull(
|
||||
resume.result.name,
|
||||
resume.result.episode,
|
||||
resume.result.season
|
||||
)
|
||||
}
|
||||
result_resume_series_progress_text?.setText(progress.progressLeft)
|
||||
result_resume_series_progress?.apply {
|
||||
isVisible = true
|
||||
this.max = progress.maxProgress
|
||||
this.progress = progress.progress
|
||||
}
|
||||
result_resume_progress_holder?.isVisible = true
|
||||
} ?: run {
|
||||
result_resume_progress_holder?.isVisible = false
|
||||
result_resume_series_progress?.isVisible = false
|
||||
result_resume_series_title?.isVisible = false
|
||||
result_resume_series_progress_text?.isVisible = false
|
||||
}
|
||||
|
||||
result_resume_series_button?.isVisible = !resume.isMovie
|
||||
result_resume_series_button_play?.isVisible = !resume.isMovie
|
||||
|
||||
val click = View.OnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(
|
||||
storedData?.playerAction ?: ACTION_PLAY_EPISODE_IN_PLAYER,
|
||||
resume.result
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
result_resume_series_button?.setOnClickListener(click)
|
||||
result_resume_series_button_play?.setOnClickListener(click)
|
||||
}
|
||||
|
||||
observe(viewModel.episodes) { episodes ->
|
||||
|
||||
|
||||
observeNullable(viewModel.episodes) { episodes ->
|
||||
updateEpisodes(episodes)
|
||||
}
|
||||
|
||||
|
@ -868,7 +877,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
setRecommendations(recommendations, null)
|
||||
}
|
||||
|
||||
observe(viewModel.movie) { data ->
|
||||
observeNullable(viewModel.movie) { data ->
|
||||
updateMovie(data)
|
||||
}
|
||||
|
||||
|
@ -1046,10 +1055,12 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}*/
|
||||
//}
|
||||
}
|
||||
|
||||
is Resource.Failure -> {
|
||||
result_error_text.text = storedData?.url?.plus("\n") + data.errorString
|
||||
updateVisStatus(1)
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
updateVisStatus(0)
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ import com.google.android.gms.cast.framework.CastState
|
|||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
|
@ -212,7 +212,6 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
}*/
|
||||
|
||||
result_mini_sync?.adapter = ImageAdapter(
|
||||
R.layout.result_mini_image,
|
||||
nextFocusDown = R.id.result_sync_set_score,
|
||||
clickCallback = { action ->
|
||||
if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {
|
||||
|
@ -271,73 +270,68 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
observe(viewModel.episodesCountText) { count ->
|
||||
observeNullable(viewModel.episodesCountText) { count ->
|
||||
result_episodes_text.setText(count)
|
||||
}
|
||||
|
||||
observe(viewModel.selectPopup) { popup ->
|
||||
when (popup) {
|
||||
is Some.Success -> {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
|
||||
popupDialog = activity?.let { act ->
|
||||
val pop = popup.value
|
||||
val options = pop.getOptions(act)
|
||||
val title = pop.getTitle(act)
|
||||
|
||||
act.showBottomDialogInstant(
|
||||
options, title, {
|
||||
popupDialog = null
|
||||
pop.callback(null)
|
||||
}, {
|
||||
popupDialog = null
|
||||
pop.callback(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
is Some.None -> {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
popupDialog = null
|
||||
}
|
||||
observeNullable(viewModel.selectPopup) { popup ->
|
||||
if (popup == null) {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
popupDialog = null
|
||||
return@observeNullable
|
||||
}
|
||||
popupDialog?.dismissSafe(activity)
|
||||
|
||||
popupDialog = activity?.let { act ->
|
||||
val options = popup.getOptions(act)
|
||||
val title = popup.getTitle(act)
|
||||
|
||||
act.showBottomDialogInstant(
|
||||
options, title, {
|
||||
popupDialog = null
|
||||
popup.callback(null)
|
||||
}, {
|
||||
popupDialog = null
|
||||
popup.callback(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
observe(viewModel.loadedLinks) { load ->
|
||||
when (load) {
|
||||
is Some.Success -> {
|
||||
if (loadingDialog?.isShowing != true) {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
}
|
||||
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
||||
val builder =
|
||||
BottomSheetDialog(ctx)
|
||||
builder.setContentView(R.layout.bottom_loading)
|
||||
builder.setOnDismissListener {
|
||||
loadingDialog = null
|
||||
viewModel.cancelLinks()
|
||||
}
|
||||
//builder.setOnCancelListener {
|
||||
// it?.dismiss()
|
||||
//}
|
||||
builder.setCanceledOnTouchOutside(true)
|
||||
builder.show()
|
||||
builder
|
||||
}
|
||||
}
|
||||
is Some.None -> {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
if (load == null) {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
return@observe
|
||||
}
|
||||
if (loadingDialog?.isShowing != true) {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
}
|
||||
loadingDialog = loadingDialog ?: context?.let { ctx ->
|
||||
val builder =
|
||||
BottomSheetDialog(ctx)
|
||||
builder.setContentView(R.layout.bottom_loading)
|
||||
builder.setOnDismissListener {
|
||||
loadingDialog = null
|
||||
viewModel.cancelLinks()
|
||||
}
|
||||
//builder.setOnCancelListener {
|
||||
// it?.dismiss()
|
||||
//}
|
||||
builder.setCanceledOnTouchOutside(true)
|
||||
builder.show()
|
||||
builder
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.selectedSeason) { text ->
|
||||
observeNullable(viewModel.selectedSeason) { text ->
|
||||
result_season_button.setText(text)
|
||||
|
||||
selectSeason =
|
||||
(if (text is Some.Success) text.value else null)?.asStringNull(result_season_button?.context)
|
||||
text?.asStringNull(result_season_button?.context)
|
||||
// If the season button is visible the result season button will be next focus down
|
||||
if (result_season_button?.isVisible == true)
|
||||
if (result_resume_parent?.isVisible == true)
|
||||
|
@ -346,7 +340,7 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
// setFocusUpAndDown(result_bookmark_button, result_season_button)
|
||||
}
|
||||
|
||||
observe(viewModel.selectedDubStatus) { status ->
|
||||
observeNullable(viewModel.selectedDubStatus) { status ->
|
||||
result_dub_select?.setText(status)
|
||||
|
||||
if (result_dub_select?.isVisible == true)
|
||||
|
@ -357,7 +351,7 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
// setFocusUpAndDown(result_bookmark_button, result_dub_select)
|
||||
}
|
||||
}
|
||||
observe(viewModel.selectedRange) { range ->
|
||||
observeNullable(viewModel.selectedRange) { range ->
|
||||
result_episode_select.setText(range)
|
||||
|
||||
// If Season button is invisible then the bookmark button next focus is episode select
|
||||
|
|
|
@ -12,9 +12,9 @@ import com.lagradost.cloudstream3.DubStatus
|
|||
import com.lagradost.cloudstream3.LoadResponse
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.mvvm.ResourceSome
|
||||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator
|
||||
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
|
@ -69,16 +69,16 @@ class ResultFragmentTv : ResultFragment() {
|
|||
return focus == this.result_root
|
||||
}
|
||||
|
||||
override fun updateEpisodes(episodes: ResourceSome<List<ResultEpisode>>) {
|
||||
override fun updateEpisodes(episodes: Resource<List<ResultEpisode>>?) {
|
||||
super.updateEpisodes(episodes)
|
||||
if (episodes is ResourceSome.Success && hasNoFocus()) {
|
||||
if (episodes is Resource.Success && hasNoFocus()) {
|
||||
result_episodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateMovie(data: ResourceSome<Pair<UiText, ResultEpisode>>) {
|
||||
override fun updateMovie(data: Resource<Pair<UiText, ResultEpisode>>?) {
|
||||
super.updateMovie(data)
|
||||
if (data is ResourceSome.Success && hasNoFocus()) {
|
||||
if (data is Resource.Success && hasNoFocus()) {
|
||||
result_play_movie?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +130,9 @@ class ResultFragmentTv : ResultFragment() {
|
|||
LinearListLayout(result_episodes?.context).apply {
|
||||
setHorizontal()
|
||||
}
|
||||
(result_episodes?.adapter as EpisodeAdapter?)?.apply {
|
||||
layout = R.layout.result_episode_both_tv
|
||||
}
|
||||
// (result_episodes?.adapter as EpisodeAdapter?)?.apply {
|
||||
// layout = R.layout.result_episode_both_tv
|
||||
// }
|
||||
//result_episodes?.setMaxViewPoolSize(0, Int.MAX_VALUE)
|
||||
|
||||
result_season_selection.setAdapter()
|
||||
|
@ -140,37 +140,37 @@ class ResultFragmentTv : ResultFragment() {
|
|||
result_dub_selection.setAdapter()
|
||||
result_recommendations_filter_selection.setAdapter()
|
||||
|
||||
observe(viewModel.selectPopup) { popup ->
|
||||
when (popup) {
|
||||
is Some.Success -> {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
observeNullable(viewModel.selectPopup) { popup ->
|
||||
if(popup == null) {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
popupDialog = null
|
||||
return@observeNullable
|
||||
}
|
||||
|
||||
popupDialog = activity?.let { act ->
|
||||
val pop = popup.value
|
||||
val options = pop.getOptions(act)
|
||||
val title = pop.getTitle(act)
|
||||
popupDialog?.dismissSafe(activity)
|
||||
|
||||
act.showBottomDialogInstant(
|
||||
options, title, {
|
||||
popupDialog = null
|
||||
pop.callback(null)
|
||||
}, {
|
||||
popupDialog = null
|
||||
pop.callback(it)
|
||||
}
|
||||
)
|
||||
popupDialog = activity?.let { act ->
|
||||
val options = popup.getOptions(act)
|
||||
val title = popup.getTitle(act)
|
||||
|
||||
act.showBottomDialogInstant(
|
||||
options, title, {
|
||||
popupDialog = null
|
||||
popup.callback(null)
|
||||
}, {
|
||||
popupDialog = null
|
||||
popup.callback(it)
|
||||
}
|
||||
}
|
||||
is Some.None -> {
|
||||
popupDialog?.dismissSafe(activity)
|
||||
popupDialog = null
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.loadedLinks) { load ->
|
||||
when (load) {
|
||||
is Some.Success -> {
|
||||
observeNullable(viewModel.loadedLinks) { load ->
|
||||
if(load == null) {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
return@observeNullable
|
||||
}
|
||||
if (loadingDialog?.isShowing != true) {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
|
@ -189,16 +189,11 @@ class ResultFragmentTv : ResultFragment() {
|
|||
builder.show()
|
||||
builder
|
||||
}
|
||||
}
|
||||
is Some.None -> {
|
||||
loadingDialog?.dismissSafe(activity)
|
||||
loadingDialog = null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
observe(viewModel.episodesCountText) { count ->
|
||||
observeNullable(viewModel.episodesCountText) { count ->
|
||||
result_episodes_text.setText(count)
|
||||
}
|
||||
|
||||
|
|
|
@ -145,15 +145,18 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
|
|||
minute
|
||||
)
|
||||
}
|
||||
|
||||
hours > 0 -> txt(
|
||||
R.string.next_episode_time_hour_format,
|
||||
hours,
|
||||
minute
|
||||
)
|
||||
|
||||
minute > 0 -> txt(
|
||||
R.string.next_episode_time_min_format,
|
||||
minute
|
||||
)
|
||||
|
||||
else -> null
|
||||
}?.also {
|
||||
nextAiringEpisode = txt(R.string.next_episode_format, airing.episode)
|
||||
|
@ -305,6 +308,7 @@ fun SelectPopup.getOptions(context: Context): List<String> {
|
|||
is SelectPopup.SelectArray -> {
|
||||
this.options.map { it.first.asString(context) }
|
||||
}
|
||||
|
||||
is SelectPopup.SelectText -> options.map { it.asString(context) }
|
||||
}
|
||||
}
|
||||
|
@ -352,17 +356,17 @@ class ResultViewModel2 : ViewModel() {
|
|||
MutableLiveData(null)
|
||||
val page: LiveData<Resource<ResultData>?> = _page
|
||||
|
||||
private val _episodes: MutableLiveData<ResourceSome<List<ResultEpisode>>> =
|
||||
MutableLiveData(ResourceSome.Loading())
|
||||
val episodes: LiveData<ResourceSome<List<ResultEpisode>>> = _episodes
|
||||
private val _episodes: MutableLiveData<Resource<List<ResultEpisode>>?> =
|
||||
MutableLiveData(Resource.Loading())
|
||||
val episodes: LiveData<Resource<List<ResultEpisode>>?> = _episodes
|
||||
|
||||
private val _movie: MutableLiveData<ResourceSome<Pair<UiText, ResultEpisode>>> =
|
||||
MutableLiveData(ResourceSome.None)
|
||||
val movie: LiveData<ResourceSome<Pair<UiText, ResultEpisode>>> = _movie
|
||||
private val _movie: MutableLiveData<Resource<Pair<UiText, ResultEpisode>>?> =
|
||||
MutableLiveData(null)
|
||||
val movie: LiveData<Resource<Pair<UiText, ResultEpisode>>?> = _movie
|
||||
|
||||
private val _episodesCountText: MutableLiveData<Some<UiText>> =
|
||||
MutableLiveData(Some.None)
|
||||
val episodesCountText: LiveData<Some<UiText>> = _episodesCountText
|
||||
private val _episodesCountText: MutableLiveData<UiText?> =
|
||||
MutableLiveData(null)
|
||||
val episodesCountText: LiveData<UiText?> = _episodesCountText
|
||||
|
||||
private val _trailers: MutableLiveData<List<ExtractedTrailerData>> =
|
||||
MutableLiveData(mutableListOf())
|
||||
|
@ -384,16 +388,16 @@ class ResultViewModel2 : ViewModel() {
|
|||
MutableLiveData(emptyList())
|
||||
val recommendations: LiveData<List<SearchResponse>> = _recommendations
|
||||
|
||||
private val _selectedRange: MutableLiveData<Some<UiText>> =
|
||||
MutableLiveData(Some.None)
|
||||
val selectedRange: LiveData<Some<UiText>> = _selectedRange
|
||||
private val _selectedRange: MutableLiveData<UiText?> =
|
||||
MutableLiveData(null)
|
||||
val selectedRange: LiveData<UiText?> = _selectedRange
|
||||
|
||||
private val _selectedSeason: MutableLiveData<Some<UiText>> =
|
||||
MutableLiveData(Some.None)
|
||||
val selectedSeason: LiveData<Some<UiText>> = _selectedSeason
|
||||
private val _selectedSeason: MutableLiveData<UiText?> =
|
||||
MutableLiveData(null)
|
||||
val selectedSeason: LiveData<UiText?> = _selectedSeason
|
||||
|
||||
private val _selectedDubStatus: MutableLiveData<Some<UiText>> = MutableLiveData(Some.None)
|
||||
val selectedDubStatus: LiveData<Some<UiText>> = _selectedDubStatus
|
||||
private val _selectedDubStatus: MutableLiveData<UiText?> = MutableLiveData(null)
|
||||
val selectedDubStatus: LiveData<UiText?> = _selectedDubStatus
|
||||
|
||||
private val _selectedRangeIndex: MutableLiveData<Int> =
|
||||
MutableLiveData(-1)
|
||||
|
@ -406,12 +410,12 @@ class ResultViewModel2 : ViewModel() {
|
|||
private val _selectedDubStatusIndex: MutableLiveData<Int> = MutableLiveData(-1)
|
||||
val selectedDubStatusIndex: LiveData<Int> = _selectedDubStatusIndex
|
||||
|
||||
private val _loadedLinks: MutableLiveData<Some<LinkProgress>> = MutableLiveData(Some.None)
|
||||
val loadedLinks: LiveData<Some<LinkProgress>> = _loadedLinks
|
||||
private val _loadedLinks: MutableLiveData<LinkProgress?> = MutableLiveData(null)
|
||||
val loadedLinks: LiveData<LinkProgress?> = _loadedLinks
|
||||
|
||||
private val _resumeWatching: MutableLiveData<Some<ResumeWatchingStatus>> =
|
||||
MutableLiveData(Some.None)
|
||||
val resumeWatching: LiveData<Some<ResumeWatchingStatus>> = _resumeWatching
|
||||
private val _resumeWatching: MutableLiveData<ResumeWatchingStatus?> =
|
||||
MutableLiveData(null)
|
||||
val resumeWatching: LiveData<ResumeWatchingStatus?> = _resumeWatching
|
||||
|
||||
private val _episodeSynopsis: MutableLiveData<String?> = MutableLiveData(null)
|
||||
val episodeSynopsis: LiveData<String?> = _episodeSynopsis
|
||||
|
@ -800,8 +804,8 @@ class ResultViewModel2 : ViewModel() {
|
|||
private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData(WatchType.NONE)
|
||||
val watchStatus: LiveData<WatchType> get() = _watchStatus
|
||||
|
||||
private val _selectPopup: MutableLiveData<Some<SelectPopup>> = MutableLiveData(Some.None)
|
||||
val selectPopup: LiveData<Some<SelectPopup>> get() = _selectPopup
|
||||
private val _selectPopup: MutableLiveData<SelectPopup?> = MutableLiveData(null)
|
||||
val selectPopup: LiveData<SelectPopup?> = _selectPopup
|
||||
|
||||
|
||||
fun updateWatchStatus(status: WatchType) {
|
||||
|
@ -885,23 +889,22 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
|
||||
fun cancelLinks() {
|
||||
println("called::cancelLinks")
|
||||
currentLoadLinkJob?.cancel()
|
||||
currentLoadLinkJob = null
|
||||
_loadedLinks.postValue(Some.None)
|
||||
_loadedLinks.postValue(null)
|
||||
}
|
||||
|
||||
private fun postPopup(text: UiText, options: List<UiText>, callback: suspend (Int?) -> Unit) {
|
||||
_selectPopup.postValue(
|
||||
some(SelectPopup.SelectText(
|
||||
SelectPopup.SelectText(
|
||||
text,
|
||||
options
|
||||
) { value ->
|
||||
viewModelScope.launchSafe {
|
||||
_selectPopup.postValue(Some.None)
|
||||
_selectPopup.postValue(null)
|
||||
callback.invoke(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -912,15 +915,15 @@ class ResultViewModel2 : ViewModel() {
|
|||
callback: suspend (Int?) -> Unit
|
||||
) {
|
||||
_selectPopup.postValue(
|
||||
some(SelectPopup.SelectArray(
|
||||
SelectPopup.SelectArray(
|
||||
text,
|
||||
options,
|
||||
) { value ->
|
||||
viewModelScope.launchSafe {
|
||||
_selectPopup.value = Some.None
|
||||
_selectPopup.postValue(null)
|
||||
callback.invoke(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -988,7 +991,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
val subs: MutableSet<SubtitleData> = mutableSetOf()
|
||||
fun updatePage() {
|
||||
if (isVisible && isActive) {
|
||||
_loadedLinks.postValue(some(LinkProgress(links.size, subs.size)))
|
||||
_loadedLinks.postValue(LinkProgress(links.size, subs.size))
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -1005,7 +1008,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
} finally {
|
||||
_loadedLinks.postValue(Some.None)
|
||||
_loadedLinks.postValue(null)
|
||||
}
|
||||
|
||||
return LinkLoadingResult(sortUrls(links), sortSubs(subs))
|
||||
|
@ -1233,6 +1236,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_CLICK_DEFAULT -> {
|
||||
activity?.let { ctx ->
|
||||
if (ctx.isConnectedToChromecast()) {
|
||||
|
@ -1249,6 +1253,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_SHOW_DESCRIPTION -> {
|
||||
_episodeSynopsis.postValue(click.data.description)
|
||||
}
|
||||
|
@ -1286,9 +1291,11 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_SHOW_TOAST -> {
|
||||
showToast(activity, R.string.play_episode_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
ACTION_DOWNLOAD_EPISODE -> {
|
||||
val response = currentResponse ?: return
|
||||
downloadEpisode(
|
||||
|
@ -1303,6 +1310,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
response.url
|
||||
)
|
||||
}
|
||||
|
||||
ACTION_DOWNLOAD_MIRROR -> {
|
||||
val response = currentResponse ?: return
|
||||
acquireSingleLink(
|
||||
|
@ -1332,6 +1340,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_RELOAD_EPISODE -> {
|
||||
ioSafe {
|
||||
loadLinks(
|
||||
|
@ -1342,6 +1351,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_CHROME_CAST_MIRROR -> {
|
||||
acquireSingleLink(
|
||||
click.data,
|
||||
|
@ -1351,6 +1361,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
startChromecast(activity, click.data, result.links, result.subs, index)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_BROWSER -> acquireSingleLink(
|
||||
click.data,
|
||||
isCasting = true,
|
||||
|
@ -1364,6 +1375,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_COPY_LINK -> {
|
||||
acquireSingleLink(
|
||||
click.data,
|
||||
|
@ -1380,9 +1392,11 @@ class ResultViewModel2 : ViewModel() {
|
|||
showToast(act, R.string.copy_link_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_CHROME_CAST_EPISODE -> {
|
||||
startChromecast(activity, click.data)
|
||||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
|
||||
loadLinks(click.data, isVisible = true, isCasting = true) { links ->
|
||||
if (links.links.isEmpty()) {
|
||||
|
@ -1397,6 +1411,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_WEB_VIDEO -> acquireSingleLink(
|
||||
click.data,
|
||||
isCasting = true,
|
||||
|
@ -1413,6 +1428,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
result.subs
|
||||
)
|
||||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_MPV -> acquireSingleLink(
|
||||
click.data,
|
||||
isCasting = true,
|
||||
|
@ -1428,6 +1444,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
result.subs
|
||||
)
|
||||
}
|
||||
|
||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||
val data = currentResponse?.syncData?.toList() ?: emptyList()
|
||||
val list =
|
||||
|
@ -1448,6 +1465,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
ACTION_MARK_AS_WATCHED -> {
|
||||
val isWatched =
|
||||
DataStoreHelper.getVideoWatchState(click.data.id) == VideoWatchState.Watched
|
||||
|
@ -1672,10 +1690,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
|
||||
private fun postMovie() {
|
||||
val response = currentResponse
|
||||
_episodes.postValue(ResourceSome.None)
|
||||
_episodes.postValue(null)
|
||||
|
||||
if (response == null) {
|
||||
_movie.postValue(ResourceSome.None)
|
||||
_movie.postValue(null)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1692,11 +1710,11 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
)
|
||||
val data = getMovie()
|
||||
_episodes.postValue(ResourceSome.None)
|
||||
_episodes.postValue(null)
|
||||
if (text == null || data == null) {
|
||||
_movie.postValue(ResourceSome.None)
|
||||
_movie.postValue(null)
|
||||
} else {
|
||||
_movie.postValue(ResourceSome.Success(text to data))
|
||||
_movie.postValue(Resource.Success(text to data))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1705,14 +1723,14 @@ class ResultViewModel2 : ViewModel() {
|
|||
postMovie()
|
||||
} else {
|
||||
_episodes.postValue(
|
||||
ResourceSome.Success(
|
||||
Resource.Success(
|
||||
getEpisodes(
|
||||
currentIndex ?: return,
|
||||
currentRange ?: return
|
||||
)
|
||||
)
|
||||
)
|
||||
_movie.postValue(ResourceSome.None)
|
||||
_movie.postValue(null)
|
||||
}
|
||||
postResume()
|
||||
}
|
||||
|
@ -1755,14 +1773,14 @@ class ResultViewModel2 : ViewModel() {
|
|||
|
||||
val size = currentEpisodes[indexer]?.size
|
||||
_episodesCountText.postValue(
|
||||
some(
|
||||
if (isMovie) null else
|
||||
txt(
|
||||
R.string.episode_format,
|
||||
size,
|
||||
txt(if (size == 1) R.string.episode else R.string.episodes),
|
||||
)
|
||||
)
|
||||
|
||||
if (isMovie) null else
|
||||
txt(
|
||||
R.string.episode_format,
|
||||
size,
|
||||
txt(if (size == 1) R.string.episode else R.string.episodes),
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
_selectedSeasonIndex.postValue(
|
||||
|
@ -1770,29 +1788,29 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
|
||||
_selectedSeason.postValue(
|
||||
some(
|
||||
if (isMovie || currentSeasons.size <= 1) null else
|
||||
when (indexer.season) {
|
||||
0 -> txt(R.string.no_season)
|
||||
else -> {
|
||||
val seasonNames = (currentResponse as? EpisodeResponse)?.seasonNames
|
||||
val seasonData = seasonNames.getSeason(indexer.season)
|
||||
|
||||
// If displaySeason is null then only show the name!
|
||||
if (seasonData?.name != null && seasonData.displaySeason == null) {
|
||||
txt(seasonData.name)
|
||||
} else {
|
||||
val suffix = seasonData?.name?.let { " $it" } ?: ""
|
||||
txt(
|
||||
R.string.season_format,
|
||||
txt(R.string.season),
|
||||
seasonData?.displaySeason ?: indexer.season,
|
||||
suffix
|
||||
)
|
||||
}
|
||||
if (isMovie || currentSeasons.size <= 1) null else
|
||||
when (indexer.season) {
|
||||
0 -> txt(R.string.no_season)
|
||||
else -> {
|
||||
val seasonNames = (currentResponse as? EpisodeResponse)?.seasonNames
|
||||
val seasonData = seasonNames.getSeason(indexer.season)
|
||||
|
||||
// If displaySeason is null then only show the name!
|
||||
if (seasonData?.name != null && seasonData.displaySeason == null) {
|
||||
txt(seasonData.name)
|
||||
} else {
|
||||
val suffix = seasonData?.name?.let { " $it" } ?: ""
|
||||
txt(
|
||||
R.string.season_format,
|
||||
txt(R.string.season),
|
||||
seasonData?.displaySeason ?: indexer.season,
|
||||
suffix
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
_selectedRangeIndex.postValue(
|
||||
|
@ -1800,13 +1818,13 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
|
||||
_selectedRange.postValue(
|
||||
some(
|
||||
if (isMovie) null else if ((currentRanges[indexer]?.size ?: 0) > 1) {
|
||||
txt(R.string.episodes_range, range.startEpisode, range.endEpisode)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
)
|
||||
|
||||
if (isMovie) null else if ((currentRanges[indexer]?.size ?: 0) > 1) {
|
||||
txt(R.string.episodes_range, range.startEpisode, range.endEpisode)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
_selectedDubStatusIndex.postValue(
|
||||
|
@ -1814,10 +1832,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
|
||||
_selectedDubStatus.postValue(
|
||||
some(
|
||||
if (isMovie || currentDubStatus.size <= 1) null else
|
||||
txt(indexer.dubStatus)
|
||||
)
|
||||
|
||||
if (isMovie || currentDubStatus.size <= 1) null else
|
||||
txt(indexer.dubStatus)
|
||||
|
||||
)
|
||||
|
||||
currentId?.let { id ->
|
||||
|
@ -1851,7 +1869,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
|
||||
}
|
||||
}*/
|
||||
_episodes.postValue(ResourceSome.Success(ret))
|
||||
_episodes.postValue(Resource.Success(ret))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1869,7 +1887,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
|
||||
private suspend fun postEpisodes(loadResponse: LoadResponse, updateFillers: Boolean) {
|
||||
_episodes.postValue(ResourceSome.Loading())
|
||||
_episodes.postValue(Resource.Loading())
|
||||
|
||||
val mainId = loadResponse.getId()
|
||||
currentId = mainId
|
||||
|
@ -1924,6 +1942,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
episodes
|
||||
}
|
||||
|
||||
is TvSeriesLoadResponse -> {
|
||||
val episodes: MutableMap<EpisodeIndexer, MutableList<ResultEpisode>> =
|
||||
mutableMapOf()
|
||||
|
@ -1968,6 +1987,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
episodes
|
||||
}
|
||||
|
||||
is MovieLoadResponse -> {
|
||||
singleMap(
|
||||
buildResultEpisode(
|
||||
|
@ -1989,6 +2009,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
is LiveStreamLoadResponse -> {
|
||||
singleMap(
|
||||
buildResultEpisode(
|
||||
|
@ -2010,6 +2031,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
is TorrentLoadResponse -> {
|
||||
singleMap(
|
||||
buildResultEpisode(
|
||||
|
@ -2031,6 +2053,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
mapOf()
|
||||
}
|
||||
|
@ -2088,7 +2111,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
|
||||
fun postResume() {
|
||||
_resumeWatching.postValue(some(resume()))
|
||||
_resumeWatching.postValue(resume())
|
||||
}
|
||||
|
||||
private fun resume(): ResumeWatchingStatus? {
|
||||
|
@ -2196,6 +2219,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
START_ACTION_LOAD_EP -> {
|
||||
val all = currentEpisodes.values.flatten()
|
||||
val episode =
|
||||
|
@ -2227,7 +2251,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
) =
|
||||
ioSafe {
|
||||
_page.postValue(Resource.Loading(url))
|
||||
_episodes.postValue(ResourceSome.Loading())
|
||||
_episodes.postValue(Resource.Loading())
|
||||
|
||||
preferDubStatus = dubStatus
|
||||
currentShowFillers = showFillers
|
||||
|
@ -2271,6 +2295,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
is Resource.Failure -> {
|
||||
_page.postValue(data)
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
if (!isActive) return@ioSafe
|
||||
val loadResponse = ioWork {
|
||||
|
@ -2307,6 +2332,7 @@ class ResultViewModel2 : ViewModel() {
|
|||
if (!isActive) return@ioSafe
|
||||
handleAutoStart(activity, autostart)
|
||||
}
|
||||
|
||||
is Resource.Loading -> {
|
||||
debugException { "Invalid load result" }
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.ResultSelectionBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
|
||||
typealias SelectData = Pair<UiText?, Any>
|
||||
|
@ -17,7 +16,9 @@ class SelectAdaptor(val callback: (Any) -> Unit) : RecyclerView.Adapter<Recycler
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return SelectViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(R.layout.result_selection, parent, false),
|
||||
ResultSelectionBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
|
||||
//LayoutInflater.from(parent.context).inflate(R.layout.result_selection, parent, false),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -73,10 +74,10 @@ class SelectAdaptor(val callback: (Any) -> Unit) : RecyclerView.Adapter<Recycler
|
|||
|
||||
private class SelectViewHolder
|
||||
constructor(
|
||||
itemView: View,
|
||||
binding: ResultSelectionBinding,
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private val item: MaterialButton = itemView as MaterialButton
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
private val item: MaterialButton = binding.root
|
||||
|
||||
fun update(isSelected: Boolean) {
|
||||
item.isSelected = isSelected
|
||||
|
|
|
@ -8,7 +8,6 @@ import androidx.annotation.DrawableRes
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
@ -162,11 +161,3 @@ fun TextView?.setTextHtml(text: UiText?) {
|
|||
this.text = str.html()
|
||||
}
|
||||
}
|
||||
|
||||
fun TextView?.setTextHtml(text: Some<UiText>?) {
|
||||
setTextHtml(if (text is Some.Success) text.value else null)
|
||||
}
|
||||
|
||||
fun TextView?.setText(text: Some<UiText>?) {
|
||||
setText(if (text is Some.Success) text.value else null)
|
||||
}
|
|
@ -78,7 +78,7 @@ class SearchAdapter(
|
|||
resView: AutofitRecyclerView
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: ImageView = itemView.imageView
|
||||
private val cardView: ImageView = itemView.imageView
|
||||
|
||||
private val compactView = false//itemView.context.getGridIsCompact()
|
||||
private val coverHeight: Int =
|
||||
|
|
|
@ -33,6 +33,8 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
|||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
||||
import com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
|
@ -56,8 +58,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import kotlinx.android.synthetic.main.fragment_search.*
|
||||
import kotlinx.android.synthetic.main.tvtypes_chips.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
const val SEARCH_PREF_TAGS = "search_pref_tags"
|
||||
|
@ -89,6 +89,7 @@ class SearchFragment : Fragment() {
|
|||
|
||||
private val searchViewModel: SearchViewModel by activityViewModels()
|
||||
private var bottomSheetDialog: BottomSheetDialog? = null
|
||||
var binding: FragmentSearchBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -99,18 +100,20 @@ class SearchFragment : Fragment() {
|
|||
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
|
||||
)
|
||||
bottomSheetDialog?.ownShow()
|
||||
return inflater.inflate(
|
||||
if (isTvSettings()) R.layout.fragment_search_tv else R.layout.fragment_search,
|
||||
container,
|
||||
false
|
||||
)
|
||||
|
||||
val layout = if (isTvSettings()) R.layout.fragment_search_tv else R.layout.fragment_search
|
||||
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
binding = FragmentSearchBinding.bind(root)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
private fun fixGrid() {
|
||||
activity?.getSpanCount()?.let {
|
||||
currentSpan = it
|
||||
}
|
||||
search_autofit_results.spanCount = currentSpan
|
||||
binding?.searchAutofitResults?.spanCount = currentSpan
|
||||
currentSpan = currentSpan
|
||||
HomeFragment.configEvent.invoke(currentSpan)
|
||||
}
|
||||
|
@ -123,6 +126,7 @@ class SearchFragment : Fragment() {
|
|||
override fun onDestroyView() {
|
||||
hideKeyboard()
|
||||
bottomSheetDialog?.ownHide()
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
@ -181,7 +185,7 @@ class SearchFragment : Fragment() {
|
|||
searchViewModel.reloadRepos()
|
||||
context?.filterProviderByPreferredMedia()?.let { validAPIs ->
|
||||
bindChips(
|
||||
home_select_group,
|
||||
binding?.tvtypesChipsScroll?.tvtypesChips,
|
||||
selectedSearchTypes,
|
||||
validAPIs.flatMap { api -> api.supportedTypes }.distinct()
|
||||
) { list ->
|
||||
|
@ -189,7 +193,7 @@ class SearchFragment : Fragment() {
|
|||
setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
|
||||
selectedSearchTypes.clear()
|
||||
selectedSearchTypes.addAll(list)
|
||||
search(main_search?.query?.toString())
|
||||
search(binding?.mainSearch?.query?.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,24 +203,27 @@ class SearchFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
context?.fixPaddingStatusbar(searchRoot)
|
||||
fixPaddingStatusbar(binding?.searchRoot)
|
||||
fixGrid()
|
||||
reloadRepos()
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let {
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
search_autofit_results,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
}
|
||||
binding?.apply {
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
searchAutofitResults,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
}
|
||||
|
||||
|
||||
searchAutofitResults.adapter = adapter
|
||||
searchLoadingBar.alpha = 0f
|
||||
}
|
||||
|
||||
search_autofit_results.adapter = adapter
|
||||
search_loading_bar.alpha = 0f
|
||||
|
||||
val searchExitIcon =
|
||||
main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||
binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||
// val searchMagIcon =
|
||||
// main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
||||
//searchMagIcon.scaleX = 0.65f
|
||||
|
@ -230,7 +237,7 @@ class SearchFragment : Fragment() {
|
|||
)!!.toMutableSet()
|
||||
}
|
||||
|
||||
search_filter.setOnClickListener { searchView ->
|
||||
binding?.searchFilter?.setOnClickListener { searchView ->
|
||||
searchView?.context?.let { ctx ->
|
||||
val validAPIs = ctx.filterProviderByPreferredMedia(hasHomePageIsRequired = false)
|
||||
var currentValidApis = listOf<MainAPI>()
|
||||
|
@ -241,7 +248,13 @@ class SearchFragment : Fragment() {
|
|||
BottomSheetDialog(ctx)
|
||||
|
||||
builder.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
builder.setContentView(R.layout.home_select_mainpage)
|
||||
|
||||
val binding: HomeSelectMainpageBinding = HomeSelectMainpageBinding.inflate(
|
||||
builder.layoutInflater,
|
||||
null,
|
||||
false
|
||||
)
|
||||
builder.setContentView(binding.root)
|
||||
builder.show()
|
||||
builder.let { dialog ->
|
||||
val isMultiLang = ctx.getApiProviderLangSettings().let { set ->
|
||||
|
@ -303,7 +316,7 @@ class SearchFragment : Fragment() {
|
|||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
||||
|
||||
bindChips(
|
||||
dialog.home_select_group,
|
||||
binding.tvtypesChipsScroll.tvtypesChips,
|
||||
selectedSearchTypes,
|
||||
TvType.values().toList()
|
||||
) { list ->
|
||||
|
@ -343,15 +356,15 @@ class SearchFragment : Fragment() {
|
|||
?: mutableListOf(TvType.Movie, TvType.TvSeries)
|
||||
|
||||
if (isTrueTvSettings()) {
|
||||
search_filter.isFocusable = true
|
||||
search_filter.isFocusableInTouchMode = true
|
||||
binding?.searchFilter?.isFocusable = true
|
||||
binding?.searchFilter?.isFocusableInTouchMode = true
|
||||
}
|
||||
|
||||
main_search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
binding?.mainSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
search(query)
|
||||
|
||||
main_search?.let {
|
||||
binding?.mainSearch?.let {
|
||||
hideKeyboard(it)
|
||||
}
|
||||
|
||||
|
@ -365,17 +378,17 @@ class SearchFragment : Fragment() {
|
|||
searchViewModel.clearSearch()
|
||||
searchViewModel.updateHistory()
|
||||
}
|
||||
|
||||
search_history_holder?.isVisible = showHistory
|
||||
|
||||
search_master_recycler?.isVisible = !showHistory && isAdvancedSearch
|
||||
search_autofit_results?.isVisible = !showHistory && !isAdvancedSearch
|
||||
binding?.apply {
|
||||
searchHistoryHolder.isVisible = showHistory
|
||||
searchMasterRecycler.isVisible = !showHistory && isAdvancedSearch
|
||||
searchAutofitResults.isVisible = !showHistory && !isAdvancedSearch
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
search_clear_call_history?.setOnClickListener {
|
||||
binding?.searchClearCallHistory?.setOnClickListener {
|
||||
activity?.let { ctx ->
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(ctx)
|
||||
val dialogClickListener =
|
||||
|
@ -409,8 +422,8 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
|
||||
observe(searchViewModel.currentHistory) { list ->
|
||||
search_clear_call_history?.isVisible = list.isNotEmpty()
|
||||
(search_history_recycler.adapter as? SearchHistoryAdaptor?)?.updateList(list)
|
||||
binding?.searchClearCallHistory?.isVisible = list.isNotEmpty()
|
||||
(binding?.searchHistoryRecycler?.adapter as? SearchHistoryAdaptor?)?.updateList(list)
|
||||
}
|
||||
|
||||
searchViewModel.updateHistory()
|
||||
|
@ -420,20 +433,20 @@ class SearchFragment : Fragment() {
|
|||
is Resource.Success -> {
|
||||
it.value.let { data ->
|
||||
if (data.isNotEmpty()) {
|
||||
(search_autofit_results?.adapter as? SearchAdapter)?.updateList(data)
|
||||
(binding?.searchAutofitResults?.adapter as? SearchAdapter)?.updateList(data)
|
||||
}
|
||||
}
|
||||
searchExitIcon.alpha = 1f
|
||||
search_loading_bar.alpha = 0f
|
||||
searchExitIcon?.alpha = 1f
|
||||
binding?.searchLoadingBar?.alpha = 0f
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
// Toast.makeText(activity, "Server error", Toast.LENGTH_LONG).show()
|
||||
searchExitIcon.alpha = 1f
|
||||
search_loading_bar.alpha = 0f
|
||||
searchExitIcon?.alpha = 1f
|
||||
binding?.searchLoadingBar?.alpha = 0f
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
searchExitIcon.alpha = 0f
|
||||
search_loading_bar.alpha = 1f
|
||||
searchExitIcon?.alpha = 0f
|
||||
binding?.searchLoadingBar?.alpha = 1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -443,7 +456,7 @@ class SearchFragment : Fragment() {
|
|||
try {
|
||||
// https://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist
|
||||
listLock.lock()
|
||||
(search_master_recycler?.adapter as ParentItemAdapter?)?.apply {
|
||||
(binding?.searchMasterRecycler?.adapter as ParentItemAdapter?)?.apply {
|
||||
val newItems = list.map { ongoing ->
|
||||
val dataList =
|
||||
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
|
||||
|
@ -490,8 +503,8 @@ class SearchFragment : Fragment() {
|
|||
SEARCH_HISTORY_OPEN -> {
|
||||
searchViewModel.clearSearch()
|
||||
if (searchItem.type.isNotEmpty())
|
||||
updateChips(home_select_group, searchItem.type.toMutableList())
|
||||
main_search?.setQuery(searchItem.searchText, true)
|
||||
updateChips(binding?.tvtypesChipsScroll?.tvtypesChips, searchItem.type.toMutableList())
|
||||
binding?.mainSearch?.setQuery(searchItem.searchText, true)
|
||||
}
|
||||
SEARCH_HISTORY_REMOVE -> {
|
||||
removeKey(SEARCH_HISTORY_KEY, searchItem.key)
|
||||
|
@ -503,20 +516,23 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
search_history_recycler?.adapter = historyAdapter
|
||||
search_history_recycler?.layoutManager = GridLayoutManager(context, 1)
|
||||
binding?.apply {
|
||||
searchHistoryRecycler.adapter = historyAdapter
|
||||
searchHistoryRecycler.layoutManager = GridLayoutManager(context, 1)
|
||||
|
||||
search_master_recycler?.adapter = masterAdapter
|
||||
search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
|
||||
searchMasterRecycler.adapter = masterAdapter
|
||||
searchMasterRecycler.layoutManager = GridLayoutManager(context, 1)
|
||||
|
||||
// Automatically search the specified query, this allows the app search to launch from intent
|
||||
arguments?.getString(SEARCH_QUERY)?.let { query ->
|
||||
if (query.isBlank()) return@let
|
||||
main_search?.setQuery(query, true)
|
||||
// Clear the query as to not make it request the same query every time the page is opened
|
||||
arguments?.putString(SEARCH_QUERY, null)
|
||||
// Automatically search the specified query, this allows the app search to launch from intent
|
||||
arguments?.getString(SEARCH_QUERY)?.let { query ->
|
||||
if (query.isBlank()) return@let
|
||||
mainSearch.setQuery(query, true)
|
||||
// Clear the query as to not make it request the same query every time the page is opened
|
||||
arguments?.putString(SEARCH_QUERY, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SubtitlesFragment.push(activity)
|
||||
//searchViewModel.search("iron man")
|
||||
//(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||
|
|
|
@ -10,7 +10,8 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import kotlinx.android.synthetic.main.search_history_item.view.*
|
||||
import com.lagradost.cloudstream3.databinding.AccountSingleBinding
|
||||
import com.lagradost.cloudstream3.databinding.SearchHistoryItemBinding
|
||||
|
||||
data class SearchHistoryItem(
|
||||
@JsonProperty("searchedAt") val searchedAt: Long,
|
||||
|
@ -34,8 +35,7 @@ class SearchHistoryAdaptor(
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return CardViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.search_history_item, parent, false),
|
||||
SearchHistoryItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
clickCallback,
|
||||
)
|
||||
}
|
||||
|
@ -65,22 +65,24 @@ class SearchHistoryAdaptor(
|
|||
|
||||
class CardViewHolder
|
||||
constructor(
|
||||
itemView: View,
|
||||
val binding: SearchHistoryItemBinding,
|
||||
private val clickCallback: (SearchHistoryCallback) -> Unit,
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private val removeButton: ImageView = itemView.home_history_remove
|
||||
private val openButton: View = itemView.home_history_tab
|
||||
private val title: TextView = itemView.home_history_title
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
// private val removeButton: ImageView = itemView.home_history_remove
|
||||
// private val openButton: View = itemView.home_history_tab
|
||||
// private val title: TextView = itemView.home_history_title
|
||||
|
||||
fun bind(card: SearchHistoryItem) {
|
||||
title.text = card.searchText
|
||||
binding.apply {
|
||||
homeHistoryTitle.text = card.searchText
|
||||
|
||||
removeButton.setOnClickListener {
|
||||
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_REMOVE))
|
||||
}
|
||||
openButton.setOnClickListener {
|
||||
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_OPEN))
|
||||
homeHistoryRemove.setOnClickListener {
|
||||
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_REMOVE))
|
||||
}
|
||||
homeHistoryTab.setOnClickListener {
|
||||
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_OPEN))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.search
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
|
@ -10,14 +9,29 @@ import androidx.cardview.widget.CardView
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.palette.graphics.Palette
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.AnimeSearchResponse
|
||||
import com.lagradost.cloudstream3.DubStatus
|
||||
import com.lagradost.cloudstream3.LiveSearchResponse
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchQuality
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.isMovieType
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.*
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.background_card
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.imageText
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.imageView
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.search_item_download_play
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.text_flag
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.text_is_dub
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.text_is_sub
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.text_quality
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.title_shadow
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.watchProgress
|
||||
|
||||
object SearchResultBuilder {
|
||||
private val showCache: MutableMap<String, Boolean> = mutableMapOf()
|
||||
|
|
|
@ -3,11 +3,10 @@ package com.lagradost.cloudstream3.ui.settings
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.AccountSingleBinding
|
||||
import com.lagradost.cloudstream3.syncproviders.AuthAPI
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
|
||||
|
@ -15,14 +14,15 @@ class AccountClickCallback(val action: Int, val view: View, val card: AuthAPI.Lo
|
|||
|
||||
class AccountAdapter(
|
||||
val cardList: List<AuthAPI.LoginInfo>,
|
||||
val layout: Int = R.layout.account_single,
|
||||
private val clickCallback: (AccountClickCallback) -> Unit
|
||||
) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return CardViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(layout, parent, false), clickCallback
|
||||
AccountSingleBinding.inflate(LayoutInflater.from(parent.context), parent, false), //LayoutInflater.from(parent.context).inflate(layout, parent, false),
|
||||
|
||||
clickCallback
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -43,18 +43,18 @@ class AccountAdapter(
|
|||
}
|
||||
|
||||
class CardViewHolder
|
||||
constructor(itemView: View, private val clickCallback: (AccountClickCallback) -> Unit) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private val pfp: ImageView = itemView.findViewById(R.id.account_profile_picture)!!
|
||||
private val accountName: TextView = itemView.findViewById(R.id.account_name)!!
|
||||
constructor(val binding: AccountSingleBinding, private val clickCallback: (AccountClickCallback) -> Unit) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
// private val pfp: ImageView = itemView.findViewById(R.id.account_profile_picture)!!
|
||||
// private val accountName: TextView = itemView.findViewById(R.id.account_name)!!
|
||||
|
||||
fun bind(card: AuthAPI.LoginInfo) {
|
||||
// just in case name is null account index will show, should never happened
|
||||
accountName.text = card.name ?: "%s %d".format(
|
||||
accountName.context.getString(R.string.account),
|
||||
binding.accountName.text = card.name ?: "%s %d".format(
|
||||
binding.accountName.context.getString(R.string.account),
|
||||
card.accountIndex
|
||||
)
|
||||
pfp.isVisible = pfp.setImage(card.profilePicture)
|
||||
binding.accountProfilePicture.isVisible = binding.accountProfilePicture.setImage(card.profilePicture)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickCallback.invoke(AccountClickCallback(0, itemView, card))
|
||||
|
|
|
@ -96,7 +96,7 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
}
|
||||
}
|
||||
api.accountIndex = ogIndex
|
||||
val adapter = AccountAdapter(items, R.layout.account_single) {
|
||||
val adapter = AccountAdapter(items) {
|
||||
dialog?.dismissSafe(activity)
|
||||
api.changeAccount(it.card.accountIndex)
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ class SettingsFragment : Fragment() {
|
|||
activity?.onBackPressed()
|
||||
}
|
||||
}
|
||||
context.fixPaddingStatusbar(settings_toolbar)
|
||||
fixPaddingStatusbar(settings_toolbar)
|
||||
}
|
||||
|
||||
fun Fragment?.setUpToolbar(@StringRes title: Int) {
|
||||
|
@ -74,7 +74,7 @@ class SettingsFragment : Fragment() {
|
|||
activity?.onBackPressed()
|
||||
}
|
||||
}
|
||||
context.fixPaddingStatusbar(settings_toolbar)
|
||||
fixPaddingStatusbar(settings_toolbar)
|
||||
}
|
||||
|
||||
fun getFolderSize(dir: File): Long {
|
||||
|
|
|
@ -18,8 +18,8 @@ import androidx.navigation.fragment.findNavController
|
|||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||
import com.lagradost.cloudstream3.ui.result.setText
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
|
@ -97,6 +97,7 @@ class ExtensionsFragment : Fragment() {
|
|||
extensionViewModel.loadRepositories()
|
||||
}
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEGATIVE -> {}
|
||||
}
|
||||
}
|
||||
|
@ -138,29 +139,26 @@ class ExtensionsFragment : Fragment() {
|
|||
// }
|
||||
// }
|
||||
|
||||
observe(extensionViewModel.pluginStats) {
|
||||
when (it) {
|
||||
is Some.Success -> {
|
||||
val value = it.value
|
||||
observeNullable(extensionViewModel.pluginStats) { value ->
|
||||
if (value == null) {
|
||||
plugin_storage_appbar?.isVisible = false
|
||||
|
||||
plugin_storage_appbar?.isVisible = true
|
||||
if (value.total == 0) {
|
||||
plugin_download?.setLayoutWidth(1)
|
||||
plugin_disabled?.setLayoutWidth(0)
|
||||
plugin_not_downloaded?.setLayoutWidth(0)
|
||||
} else {
|
||||
plugin_download?.setLayoutWidth(value.downloaded)
|
||||
plugin_disabled?.setLayoutWidth(value.disabled)
|
||||
plugin_not_downloaded?.setLayoutWidth(value.notDownloaded)
|
||||
}
|
||||
plugin_not_downloaded_txt.setText(value.notDownloadedText)
|
||||
plugin_disabled_txt.setText(value.disabledText)
|
||||
plugin_download_txt.setText(value.downloadedText)
|
||||
}
|
||||
is Some.None -> {
|
||||
plugin_storage_appbar?.isVisible = false
|
||||
}
|
||||
return@observeNullable
|
||||
}
|
||||
|
||||
plugin_storage_appbar?.isVisible = true
|
||||
if (value.total == 0) {
|
||||
plugin_download?.setLayoutWidth(1)
|
||||
plugin_disabled?.setLayoutWidth(0)
|
||||
plugin_not_downloaded?.setLayoutWidth(0)
|
||||
} else {
|
||||
plugin_download?.setLayoutWidth(value.downloaded)
|
||||
plugin_disabled?.setLayoutWidth(value.disabled)
|
||||
plugin_not_downloaded?.setLayoutWidth(value.notDownloaded)
|
||||
}
|
||||
plugin_not_downloaded_txt.setText(value.notDownloadedText)
|
||||
plugin_disabled_txt.setText(value.disabledText)
|
||||
plugin_download_txt.setText(value.downloadedText)
|
||||
}
|
||||
|
||||
plugin_storage_appbar?.setOnClickListener {
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
|||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.amap
|
||||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager.getPluginsOnline
|
||||
|
@ -40,8 +39,8 @@ class ExtensionsViewModel : ViewModel() {
|
|||
private val _repositories = MutableLiveData<Array<RepositoryData>>()
|
||||
val repositories: LiveData<Array<RepositoryData>> = _repositories
|
||||
|
||||
private val _pluginStats: MutableLiveData<Some<PluginStats>> = MutableLiveData(Some.None)
|
||||
val pluginStats: LiveData<Some<PluginStats>> = _pluginStats
|
||||
private val _pluginStats: MutableLiveData<PluginStats?> = MutableLiveData(null)
|
||||
val pluginStats: LiveData<PluginStats?> = _pluginStats
|
||||
|
||||
//TODO CACHE GET REQUESTS
|
||||
// DO not use viewModelScope.launchSafe, it will ANR on slow internet
|
||||
|
@ -78,7 +77,7 @@ class ExtensionsViewModel : ViewModel() {
|
|||
debugAssert({ stats.downloaded + stats.notDownloaded + stats.disabled != stats.total }) {
|
||||
"downloaded(${stats.downloaded}) + notDownloaded(${stats.notDownloaded}) + disabled(${stats.disabled}) != total(${stats.total})"
|
||||
}
|
||||
_pluginStats.postValue(Some.Success(stats))
|
||||
_pluginStats.postValue(stats)
|
||||
}
|
||||
|
||||
private fun repos() = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
|||
import com.lagradost.cloudstream3.AllLanguagesName
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.databinding.FragmentPluginsBinding
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
|
@ -20,9 +21,6 @@ import com.lagradost.cloudstream3.ui.settings.appLanguages
|
|||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
import kotlinx.android.synthetic.main.fragment_plugins.*
|
||||
import kotlinx.android.synthetic.main.tvtypes_chips.*
|
||||
import kotlinx.android.synthetic.main.tvtypes_chips_scroll.*
|
||||
|
||||
const val PLUGINS_BUNDLE_NAME = "name"
|
||||
const val PLUGINS_BUNDLE_URL = "url"
|
||||
|
@ -33,11 +31,19 @@ class PluginsFragment : Fragment() {
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_plugins, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentPluginsBinding.inflate(inflater,container,false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.fragment_plugins, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private val pluginViewModel: PluginsViewModel by activityViewModels()
|
||||
var binding: FragmentPluginsBinding? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -66,8 +72,8 @@ class PluginsFragment : Fragment() {
|
|||
}
|
||||
|
||||
setUpToolbar(name)
|
||||
|
||||
settings_toolbar?.setOnMenuItemClickListener { menuItem ->
|
||||
binding?.settingsToolbar?.apply {
|
||||
setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem?.itemId) {
|
||||
R.id.download_all -> {
|
||||
PluginsViewModel.downloadAll(activity, url, pluginViewModel)
|
||||
|
@ -99,67 +105,69 @@ class PluginsFragment : Fragment() {
|
|||
}
|
||||
|
||||
val searchView =
|
||||
settings_toolbar?.menu?.findItem(R.id.search_button)?.actionView as? SearchView
|
||||
menu?.findItem(R.id.search_button)?.actionView as? SearchView
|
||||
|
||||
// Don't go back if active query
|
||||
settings_toolbar?.setNavigationOnClickListener {
|
||||
setNavigationOnClickListener {
|
||||
if (searchView?.isIconified == false) {
|
||||
searchView.isIconified = true
|
||||
} else {
|
||||
activity?.onBackPressed()
|
||||
}
|
||||
}
|
||||
searchView?.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) pluginViewModel.search(null)
|
||||
}
|
||||
|
||||
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
pluginViewModel.search(query)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?): Boolean {
|
||||
pluginViewModel.search(newText)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
// searchView?.onActionViewCollapsed = {
|
||||
// pluginViewModel.search(null)
|
||||
// }
|
||||
|
||||
// Because onActionViewCollapsed doesn't wanna work we need this workaround :(
|
||||
searchView?.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) pluginViewModel.search(null)
|
||||
}
|
||||
|
||||
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
pluginViewModel.search(query)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?): Boolean {
|
||||
pluginViewModel.search(newText)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
plugin_recycler_view?.adapter =
|
||||
|
||||
binding?.pluginRecyclerView?.adapter =
|
||||
PluginAdapter {
|
||||
pluginViewModel.handlePluginAction(activity, url, it, isLocal)
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
// Scrolling down does not reveal the whole RecyclerView on TV, add to bypass that.
|
||||
plugin_recycler_view?.setPadding(0, 0, 0, 200.toPx)
|
||||
binding?.pluginRecyclerView?.setPadding(0, 0, 0, 200.toPx)
|
||||
}
|
||||
|
||||
observe(pluginViewModel.filteredPlugins) { (scrollToTop, list) ->
|
||||
(plugin_recycler_view?.adapter as? PluginAdapter)?.updateList(list)
|
||||
(binding?.pluginRecyclerView?.adapter as? PluginAdapter)?.updateList(list)
|
||||
|
||||
if (scrollToTop)
|
||||
plugin_recycler_view?.scrollToPosition(0)
|
||||
binding?.pluginRecyclerView?.scrollToPosition(0)
|
||||
}
|
||||
|
||||
if (isLocal) {
|
||||
// No download button and no categories on local
|
||||
settings_toolbar?.menu?.findItem(R.id.download_all)?.isVisible = false
|
||||
settings_toolbar?.menu?.findItem(R.id.lang_filter)?.isVisible = false
|
||||
binding?.settingsToolbar?.menu?.findItem(R.id.download_all)?.isVisible = false
|
||||
binding?.settingsToolbar?.menu?.findItem(R.id.lang_filter)?.isVisible = false
|
||||
pluginViewModel.updatePluginListLocal()
|
||||
tv_types_scroll_view?.isVisible = false
|
||||
|
||||
binding?.tvtypesChipsScroll?.root?.isVisible = false
|
||||
} else {
|
||||
pluginViewModel.updatePluginList(context, url)
|
||||
tv_types_scroll_view?.isVisible = true
|
||||
binding?.tvtypesChipsScroll?.root?.isVisible = true
|
||||
|
||||
bindChips(home_select_group, emptyList(), TvType.values().toList()) { list ->
|
||||
bindChips(binding?.tvtypesChipsScroll?.tvtypesChips, emptyList(), TvType.values().toList()) { list ->
|
||||
pluginViewModel.tvTypes.clear()
|
||||
pluginViewModel.tvTypes.addAll(list.map { it.name })
|
||||
pluginViewModel.updateFilteredPlugins()
|
||||
|
|
|
@ -8,21 +8,16 @@ import androidx.core.view.isVisible
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.lagradost.cloudstream3.APIHolder.apis
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||
import com.lagradost.cloudstream3.AllLanguagesName
|
||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSetupExtensionsBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
||||
import com.lagradost.cloudstream3.ui.settings.extensions.PluginsViewModel
|
||||
import com.lagradost.cloudstream3.ui.settings.extensions.RepoAdapter
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import kotlinx.android.synthetic.main.fragment_extensions.blank_repo_screen
|
||||
import kotlinx.android.synthetic.main.fragment_extensions.repo_recycler_view
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.next_btt
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.prev_btt
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.setup_root
|
||||
|
||||
|
||||
class SetupFragmentExtensions : Fragment() {
|
||||
|
@ -39,13 +34,24 @@ class SetupFragmentExtensions : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
var binding: FragmentSetupExtensionsBinding? = null
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_setup_extensions, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentSetupExtensionsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.fragment_setup_extensions, container, false)
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
afterRepositoryLoadedEvent += ::setRepositories
|
||||
|
@ -60,12 +66,12 @@ class SetupFragmentExtensions : Fragment() {
|
|||
main {
|
||||
val repositories = RepositoryManager.getRepositories() + PREBUILT_REPOSITORIES
|
||||
val hasRepos = repositories.isNotEmpty()
|
||||
repo_recycler_view?.isVisible = hasRepos
|
||||
blank_repo_screen?.isVisible = !hasRepos
|
||||
binding?.repoRecyclerView?.isVisible = hasRepos
|
||||
binding?.blankRepoScreen?.isVisible = !hasRepos
|
||||
// view_public_repositories_button?.isVisible = hasRepos
|
||||
|
||||
if (hasRepos) {
|
||||
repo_recycler_view?.adapter = RepoAdapter(true, {}, {
|
||||
binding?.repoRecyclerView?.adapter = RepoAdapter(true, {}, {
|
||||
PluginsViewModel.downloadAll(activity, it.url, null)
|
||||
}).apply { updateList(repositories) }
|
||||
}
|
||||
|
@ -80,39 +86,40 @@ class SetupFragmentExtensions : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(setup_root)
|
||||
fixPaddingStatusbar(binding?.setupRoot)
|
||||
val isSetup = arguments?.getBoolean(SETUP_EXTENSION_BUNDLE_IS_SETUP) ?: false
|
||||
|
||||
// view_public_repositories_button?.setOnClickListener {
|
||||
// openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
||||
// }
|
||||
|
||||
with(context) {
|
||||
if (this == null) return
|
||||
normalSafeApiCall {
|
||||
// val ctx = context ?: return@normalSafeApiCall
|
||||
setRepositories()
|
||||
binding?.apply {
|
||||
if (!isSetup) {
|
||||
nextBtt.setText(R.string.setup_done)
|
||||
}
|
||||
prevBtt.isVisible = isSetup
|
||||
|
||||
if (!isSetup) {
|
||||
next_btt.setText(R.string.setup_done)
|
||||
}
|
||||
prev_btt?.isVisible = isSetup
|
||||
nextBtt.setOnClickListener {
|
||||
// Continue setup
|
||||
if (isSetup)
|
||||
if (
|
||||
// If any available languages
|
||||
apis.distinctBy { it.lang }.size > 1
|
||||
) {
|
||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_provider_languages)
|
||||
} else {
|
||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)
|
||||
}
|
||||
else
|
||||
findNavController().navigate(R.id.navigation_home)
|
||||
}
|
||||
|
||||
next_btt?.setOnClickListener {
|
||||
// Continue setup
|
||||
if (isSetup)
|
||||
if (
|
||||
// If any available languages
|
||||
apis.distinctBy { it.lang }.size > 1
|
||||
) {
|
||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_provider_languages)
|
||||
} else {
|
||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)
|
||||
}
|
||||
else
|
||||
findNavController().navigate(R.id.navigation_home)
|
||||
}
|
||||
|
||||
prev_btt?.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_setup_language)
|
||||
prevBtt.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_setup_language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,40 +13,49 @@ import androidx.preference.PreferenceManager
|
|||
import com.lagradost.cloudstream3.BuildConfig
|
||||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSetupLanguageBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||
import com.lagradost.cloudstream3.ui.settings.appLanguages
|
||||
import com.lagradost.cloudstream3.ui.settings.getCurrentLocale
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import kotlinx.android.synthetic.main.fragment_setup_language.*
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.listview1
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.next_btt
|
||||
|
||||
const val HAS_DONE_SETUP_KEY = "HAS_DONE_SETUP"
|
||||
|
||||
class SetupFragmentLanguage : Fragment() {
|
||||
var binding: FragmentSetupLanguageBinding? = null
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_setup_language, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentSetupLanguageBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.fragment_setup_language, container, false)
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(setup_root)
|
||||
|
||||
// We don't want a crash for all users
|
||||
normalSafeApiCall {
|
||||
with(context) {
|
||||
if (this == null) return@normalSafeApiCall
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
fixPaddingStatusbar(binding?.setupRoot)
|
||||
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
|
||||
val ctx = context ?: return@normalSafeApiCall
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
||||
binding?.apply {
|
||||
// Icons may crash on some weird android versions?
|
||||
normalSafeApiCall {
|
||||
val drawable = when {
|
||||
|
@ -54,10 +63,10 @@ class SetupFragmentLanguage : Fragment() {
|
|||
BuildConfig.BUILD_TYPE == "prerelease" -> R.drawable.cloud_2_gradient_beta
|
||||
else -> R.drawable.cloud_2_gradient
|
||||
}
|
||||
app_icon_image?.setImageDrawable(ContextCompat.getDrawable(this, drawable))
|
||||
appIconImage.setImageDrawable(ContextCompat.getDrawable(ctx, drawable))
|
||||
}
|
||||
|
||||
val current = getCurrentLocale(this)
|
||||
val current = getCurrentLocale(ctx)
|
||||
val languageCodes = appLanguages.map { it.third }
|
||||
val languageNames = appLanguages.map { (emoji, name, iso) ->
|
||||
val flag = emoji.ifBlank { SubtitleHelper.getFlagFromIso(iso) ?: "ERROR" }
|
||||
|
@ -66,18 +75,19 @@ class SetupFragmentLanguage : Fragment() {
|
|||
val index = languageCodes.indexOf(current)
|
||||
|
||||
arrayAdapter.addAll(languageNames)
|
||||
listview1?.adapter = arrayAdapter
|
||||
listview1?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
listview1?.setItemChecked(index, true)
|
||||
listview1.adapter = arrayAdapter
|
||||
listview1.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
listview1.setItemChecked(index, true)
|
||||
|
||||
listview1?.setOnItemClickListener { _, _, position, _ ->
|
||||
listview1.setOnItemClickListener { _, _, position, _ ->
|
||||
val code = languageCodes[position]
|
||||
CommonActivity.setLocale(activity, code)
|
||||
settingsManager.edit().putString(getString(R.string.locale_key), code).apply()
|
||||
settingsManager.edit().putString(getString(R.string.locale_key), code)
|
||||
.apply()
|
||||
activity?.recreate()
|
||||
}
|
||||
|
||||
next_btt?.setOnClickListener {
|
||||
nextBtt.setOnClickListener {
|
||||
// If no plugins go to plugins page
|
||||
val nextDestination = if (
|
||||
PluginManager.getPluginsOnline().isEmpty()
|
||||
|
@ -92,10 +102,11 @@ class SetupFragmentLanguage : Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
skip_btt?.setOnClickListener {
|
||||
skipBtt.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_home)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,30 +10,39 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSetupLayoutBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import kotlinx.android.synthetic.main.fragment_setup_layout.*
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.listview1
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.next_btt
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.prev_btt
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.setup_root
|
||||
import org.acra.ACRA
|
||||
|
||||
|
||||
class SetupFragmentLayout : Fragment() {
|
||||
|
||||
var binding: FragmentSetupLayoutBinding? = null
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_setup_layout, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentSetupLayoutBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.fragment_setup_layout, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(setup_root)
|
||||
fixPaddingStatusbar(binding?.setupRoot)
|
||||
|
||||
with(context) {
|
||||
if (this == null) return
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
normalSafeApiCall {
|
||||
val ctx = context ?: return@normalSafeApiCall
|
||||
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
|
||||
val prefNames = resources.getStringArray(R.array.app_layout)
|
||||
val prefValues = resources.getIntArray(R.array.app_layout_values)
|
||||
|
@ -42,48 +51,48 @@ class SetupFragmentLayout : Fragment() {
|
|||
settingsManager.getInt(getString(R.string.app_layout_key), -1)
|
||||
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
||||
arrayAdapter.addAll(prefNames.toList())
|
||||
listview1?.adapter = arrayAdapter
|
||||
listview1?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
listview1?.setItemChecked(
|
||||
prefValues.indexOf(currentLayout), true
|
||||
)
|
||||
|
||||
listview1?.setOnItemClickListener { _, _, position, _ ->
|
||||
settingsManager.edit()
|
||||
.putInt(getString(R.string.app_layout_key), prefValues[position])
|
||||
.apply()
|
||||
activity?.recreate()
|
||||
}
|
||||
|
||||
acra_switch?.setOnCheckedChangeListener { _, enableCrashReporting ->
|
||||
// Use same pref as in settings
|
||||
settingsManager.edit().putBoolean(ACRA.PREF_DISABLE_ACRA, !enableCrashReporting)
|
||||
.apply()
|
||||
val text =
|
||||
if (enableCrashReporting) R.string.bug_report_settings_off else R.string.bug_report_settings_on
|
||||
crash_reporting_text?.text = getText(text)
|
||||
}
|
||||
|
||||
val enableCrashReporting = !settingsManager.getBoolean(ACRA.PREF_DISABLE_ACRA, true)
|
||||
acra_switch.isChecked = enableCrashReporting
|
||||
crash_reporting_text.text =
|
||||
getText(
|
||||
if (enableCrashReporting) R.string.bug_report_settings_off else R.string.bug_report_settings_on
|
||||
binding?.apply {
|
||||
listview1.adapter = arrayAdapter
|
||||
listview1.choiceMode = AbsListView.CHOICE_MODE_SINGLE
|
||||
listview1.setItemChecked(
|
||||
prefValues.indexOf(currentLayout), true
|
||||
)
|
||||
|
||||
listview1.setOnItemClickListener { _, _, position, _ ->
|
||||
settingsManager.edit()
|
||||
.putInt(getString(R.string.app_layout_key), prefValues[position])
|
||||
.apply()
|
||||
activity?.recreate()
|
||||
}
|
||||
acraSwitch.setOnCheckedChangeListener { _, enableCrashReporting ->
|
||||
// Use same pref as in settings
|
||||
settingsManager.edit().putBoolean(ACRA.PREF_DISABLE_ACRA, !enableCrashReporting)
|
||||
.apply()
|
||||
val text =
|
||||
if (enableCrashReporting) R.string.bug_report_settings_off else R.string.bug_report_settings_on
|
||||
crashReportingText.text = getText(text)
|
||||
}
|
||||
|
||||
next_btt?.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_home)
|
||||
}
|
||||
val enableCrashReporting = !settingsManager.getBoolean(ACRA.PREF_DISABLE_ACRA, true)
|
||||
|
||||
prev_btt?.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
acraSwitch.isChecked = enableCrashReporting
|
||||
crashReportingText.text =
|
||||
getText(
|
||||
if (enableCrashReporting) R.string.bug_report_settings_off else R.string.bug_report_settings_on
|
||||
)
|
||||
|
||||
|
||||
nextBtt.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_home)
|
||||
}
|
||||
|
||||
prevBtt.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,72 +10,85 @@ import androidx.core.util.forEach
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSetupMediaBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.*
|
||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
||||
|
||||
|
||||
class SetupFragmentMedia : Fragment() {
|
||||
var binding: FragmentSetupMediaBinding? = null
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_setup_media, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentSetupMediaBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.fragment_setup_media, container, false)
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(setup_root)
|
||||
normalSafeApiCall {
|
||||
fixPaddingStatusbar(binding?.setupRoot)
|
||||
|
||||
with(context) {
|
||||
if (this == null) return
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val ctx = context ?: return@normalSafeApiCall
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
||||
val names = enumValues<TvType>().sorted().map { it.name }
|
||||
val selected = mutableListOf<Int>()
|
||||
|
||||
arrayAdapter.addAll(names)
|
||||
listview1?.let {
|
||||
it.adapter = arrayAdapter
|
||||
it.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
|
||||
binding?.apply {
|
||||
listview1.let {
|
||||
it.adapter = arrayAdapter
|
||||
it.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
|
||||
|
||||
it.setOnItemClickListener { _, _, _, _ ->
|
||||
it.checkedItemPositions?.forEach { key, value ->
|
||||
if (value) {
|
||||
selected.add(key)
|
||||
} else {
|
||||
selected.remove(key)
|
||||
it.setOnItemClickListener { _, _, _, _ ->
|
||||
it.checkedItemPositions?.forEach { key, value ->
|
||||
if (value) {
|
||||
selected.add(key)
|
||||
} else {
|
||||
selected.remove(key)
|
||||
}
|
||||
}
|
||||
val prefValues = selected.mapNotNull { pos ->
|
||||
val item =
|
||||
it.getItemAtPosition(pos)?.toString() ?: return@mapNotNull null
|
||||
val itemVal = TvType.valueOf(item)
|
||||
itemVal.ordinal.toString()
|
||||
}.toSet()
|
||||
settingsManager.edit()
|
||||
.putStringSet(getString(R.string.prefer_media_type_key), prefValues)
|
||||
.apply()
|
||||
|
||||
// Regenerate set homepage
|
||||
removeKey(USER_SELECTED_HOMEPAGE_API)
|
||||
}
|
||||
val prefValues = selected.mapNotNull { pos ->
|
||||
val item = it.getItemAtPosition(pos)?.toString() ?: return@mapNotNull null
|
||||
val itemVal = TvType.valueOf(item)
|
||||
itemVal.ordinal.toString()
|
||||
}.toSet()
|
||||
settingsManager.edit()
|
||||
.putStringSet(getString(R.string.prefer_media_type_key), prefValues)
|
||||
.apply()
|
||||
|
||||
// Regenerate set homepage
|
||||
removeKey(USER_SELECTED_HOMEPAGE_API)
|
||||
}
|
||||
}
|
||||
|
||||
next_btt?.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_setup_media_to_navigation_setup_layout)
|
||||
}
|
||||
nextBtt.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_setup_media_to_navigation_setup_layout)
|
||||
}
|
||||
|
||||
prev_btt?.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
prevBtt.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,31 +14,43 @@ import com.lagradost.cloudstream3.APIHolder
|
|||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||
import com.lagradost.cloudstream3.AllLanguagesName
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentSetupProviderLanguagesBinding
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||
import kotlinx.android.synthetic.main.fragment_setup_media.*
|
||||
|
||||
class SetupFragmentProviderLanguage : Fragment() {
|
||||
var binding: FragmentSetupProviderLanguagesBinding? = null
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_setup_provider_languages, container, false)
|
||||
): View {
|
||||
val localBinding = FragmentSetupProviderLanguagesBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
//return inflater.inflate(R.layout.fragment_setup_provider_languages, container, false)
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
context?.fixPaddingStatusbar(setup_root)
|
||||
fixPaddingStatusbar(binding?.setupRoot)
|
||||
|
||||
with(context) {
|
||||
if (this == null) return
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
normalSafeApiCall {
|
||||
val ctx = context ?: return@normalSafeApiCall
|
||||
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
|
||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
||||
val current = this.getApiProviderLangSettings()
|
||||
val current = ctx.getApiProviderLangSettings()
|
||||
val langs = APIHolder.apis.map { it.lang }.toSet()
|
||||
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) } + AllLanguagesName
|
||||
|
||||
|
@ -56,31 +68,31 @@ class SetupFragmentProviderLanguage : Fragment() {
|
|||
}
|
||||
|
||||
arrayAdapter.addAll(languageNames)
|
||||
|
||||
listview1?.adapter = arrayAdapter
|
||||
listview1?.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
|
||||
binding?.apply {
|
||||
listview1.adapter = arrayAdapter
|
||||
listview1.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
|
||||
currentList.forEach {
|
||||
listview1.setItemChecked(it, true)
|
||||
}
|
||||
|
||||
listview1?.setOnItemClickListener { _, _, _, _ ->
|
||||
listview1.setOnItemClickListener { _, _, _, _ ->
|
||||
val currentLanguages = mutableListOf<String>()
|
||||
listview1?.checkedItemPositions?.forEach { key, value ->
|
||||
listview1.checkedItemPositions?.forEach { key, value ->
|
||||
if (value) currentLanguages.add(langs[key])
|
||||
}
|
||||
settingsManager.edit().putStringSet(
|
||||
this.getString(R.string.provider_lang_key),
|
||||
ctx.getString(R.string.provider_lang_key),
|
||||
currentLanguages.toSet()
|
||||
).apply()
|
||||
}
|
||||
|
||||
next_btt?.setOnClickListener {
|
||||
nextBtt.setOnClickListener {
|
||||
findNavController().navigate(R.id.navigation_setup_provider_languages_to_navigation_setup_media)
|
||||
}
|
||||
|
||||
prev_btt?.setOnClickListener {
|
||||
prevBtt.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
|||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.ChromecastSubtitleSettingsBinding
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||
import com.lagradost.cloudstream3.utils.Event
|
||||
|
@ -31,7 +32,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||
import kotlinx.android.synthetic.main.subtitle_settings.*
|
||||
|
||||
const val CHROME_SUBTITLE_KEY = "chome_subtitle_settings"
|
||||
|
||||
|
@ -137,12 +137,21 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
//subtitle_text?.setStyle(fromSaveToStyle(state))
|
||||
}
|
||||
|
||||
var binding : ChromecastSubtitleSettingsBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.chromecast_subtitle_settings, container, false)
|
||||
): View {
|
||||
val localBinding = ChromecastSubtitleSettingsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.chromecast_subtitle_settings, container, false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private lateinit var state: SaveChromeCaptionStyle
|
||||
|
@ -159,7 +168,7 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
onColorSelectedEvent += ::onColorSelected
|
||||
onDialogDismissedEvent += ::onDialogDismissed
|
||||
|
||||
context?.fixPaddingStatusbar(subs_root)
|
||||
fixPaddingStatusbar(binding?.subsRoot)
|
||||
|
||||
state = getCurrentSavedStyle()
|
||||
context?.updateState()
|
||||
|
@ -190,17 +199,20 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
subs_text_color.setup(0)
|
||||
subs_outline_color.setup(1)
|
||||
subs_background_color.setup(2)
|
||||
binding?.apply {
|
||||
subsTextColor.setup(0)
|
||||
subsOutlineColor.setup(1)
|
||||
subsBackgroundColor.setup(2)
|
||||
}
|
||||
|
||||
|
||||
val dismissCallback = {
|
||||
if (hide)
|
||||
activity?.hideSystemUI()
|
||||
}
|
||||
|
||||
subs_edge_type.setFocusableInTv()
|
||||
subs_edge_type.setOnClickListener { textView ->
|
||||
binding?.subsEdgeType?.setFocusableInTv()
|
||||
binding?.subsEdgeType?.setOnClickListener { textView ->
|
||||
val edgeTypes = listOf(
|
||||
Pair(
|
||||
EDGE_TYPE_NONE,
|
||||
|
@ -237,15 +249,15 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
subs_edge_type.setOnLongClickListener {
|
||||
binding?.subsEdgeType?.setOnLongClickListener {
|
||||
state.edgeType = defaultState.edgeType
|
||||
it.context.updateState()
|
||||
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
subs_font_size.setFocusableInTv()
|
||||
subs_font_size.setOnClickListener { textView ->
|
||||
binding?.subsFontSize?.setFocusableInTv()
|
||||
binding?.subsFontSize?.setOnClickListener { textView ->
|
||||
val fontSizes = listOf(
|
||||
Pair(0.75f, "75%"),
|
||||
Pair(0.80f, "80%"),
|
||||
|
@ -278,24 +290,26 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
subs_font_size.setOnLongClickListener { _ ->
|
||||
binding?.subsFontSize?.setOnLongClickListener { _ ->
|
||||
state.fontScale = defaultState.fontScale
|
||||
//textView.context.updateState() // font size not changed
|
||||
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
subs_font.setFocusableInTv()
|
||||
subs_font.setOnClickListener { textView ->
|
||||
|
||||
|
||||
binding?.subsFont?.setFocusableInTv()
|
||||
binding?.subsFont?.setOnClickListener { textView ->
|
||||
val fontTypes = listOf(
|
||||
Pair(null, textView.context.getString(R.string.normal)),
|
||||
Pair("Droid Sans", "Droid Sans"),
|
||||
Pair("Droid Sans Mono", "Droid Sans Mono"),
|
||||
Pair("Droid Serif Regular", "Droid Serif Regular"),
|
||||
Pair("Cutive Mono", "Cutive Mono"),
|
||||
Pair("Short Stack", "Short Stack"),
|
||||
Pair("Quintessential", "Quintessential"),
|
||||
Pair("Alegreya Sans SC", "Alegreya Sans SC"),
|
||||
null to textView.context.getString(R.string.normal),
|
||||
"Droid Sans" to "Droid Sans",
|
||||
"Droid Sans Mono" to "Droid Sans Mono",
|
||||
"Droid Serif Regular" to "Droid Serif Regular",
|
||||
"Cutive Mono" to "Cutive Mono",
|
||||
"Short Stack" to "Short Stack",
|
||||
"Quintessential" to "Quintessential",
|
||||
"Alegreya Sans SC" to "Alegreya Sans SC",
|
||||
)
|
||||
|
||||
//showBottomDialog
|
||||
|
@ -310,35 +324,35 @@ class ChromecastSubtitlesFragment : Fragment() {
|
|||
textView.context.updateState()
|
||||
}
|
||||
}
|
||||
|
||||
subs_font.setOnLongClickListener { textView ->
|
||||
binding?.subsFont?.setOnLongClickListener { textView ->
|
||||
state.fontFamily = defaultState.fontFamily
|
||||
textView.context.updateState()
|
||||
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
cancel_btt.setOnClickListener {
|
||||
binding?.cancelBtt?.setOnClickListener {
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
apply_btt.setOnClickListener {
|
||||
binding?.applyBtt?.setOnClickListener {
|
||||
it.context.saveStyle(state)
|
||||
applyStyleEvent.invoke(state)
|
||||
//it.context.fromSaveToStyle(state)
|
||||
activity?.popCurrentPage()
|
||||
}
|
||||
|
||||
subtitle_text.setCues(
|
||||
listOf(
|
||||
Cue.Builder()
|
||||
.setTextSize(
|
||||
getPixels(TypedValue.COMPLEX_UNIT_SP, 25.0f).toFloat(),
|
||||
Cue.TEXT_SIZE_TYPE_ABSOLUTE
|
||||
)
|
||||
.setText(subtitle_text.context.getString(R.string.subtitles_example_text))
|
||||
.build()
|
||||
binding?.subtitleText?.apply {
|
||||
setCues(
|
||||
listOf(
|
||||
Cue.Builder()
|
||||
.setTextSize(
|
||||
getPixels(TypedValue.COMPLEX_UNIT_SP, 25.0f).toFloat(),
|
||||
Cue.TEXT_SIZE_TYPE_ABSOLUTE
|
||||
)
|
||||
.setText(context.getString(R.string.subtitles_example_text))
|
||||
.build()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ class SubtitlesFragment : Fragment() {
|
|||
context?.getExternalFilesDir(null)?.absolutePath.toString() + "/Fonts"
|
||||
)
|
||||
|
||||
context?.fixPaddingStatusbar(subs_root)
|
||||
fixPaddingStatusbar(subs_root)
|
||||
|
||||
state = getCurrentSavedStyle()
|
||||
context?.updateState()
|
||||
|
|
|
@ -397,21 +397,22 @@ object UIHelper {
|
|||
return result
|
||||
}
|
||||
|
||||
fun Context?.fixPaddingStatusbar(v: View?) {
|
||||
if (v == null || this == null) return
|
||||
fun fixPaddingStatusbar(v: View?) {
|
||||
if (v == null) return
|
||||
val ctx = v.context ?: return
|
||||
v.setPadding(
|
||||
v.paddingLeft,
|
||||
v.paddingTop + getStatusBarHeight(),
|
||||
v.paddingTop + ctx.getStatusBarHeight(),
|
||||
v.paddingRight,
|
||||
v.paddingBottom
|
||||
)
|
||||
}
|
||||
|
||||
fun Context.fixPaddingStatusbarView(v: View?) {
|
||||
fun fixPaddingStatusbarView(v: View?) {
|
||||
if (v == null) return
|
||||
|
||||
val ctx = v.context ?: return
|
||||
val params = v.layoutParams
|
||||
params.height = getStatusBarHeight()
|
||||
params.height = ctx.getStatusBarHeight()
|
||||
v.layoutParams = params
|
||||
}
|
||||
|
||||
|
|
|
@ -172,4 +172,15 @@
|
|||
app:icon="@drawable/ic_baseline_filter_list_24"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/home_random"
|
||||
style="@style/ExtendedFloatingActionButton"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:text="@string/home_random"
|
||||
android:textColor="?attr/textColor"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
</FrameLayout>
|
|
@ -25,7 +25,7 @@
|
|||
app:titleTextColor="?attr/textColor"
|
||||
tools:title="Overlord" />
|
||||
|
||||
<include layout="@layout/tvtypes_chips_scroll" />
|
||||
<include layout="@layout/tvtypes_chips_scroll" android:id="@+id/tvtypes_chips_scroll" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
<include layout="@layout/tvtypes_chips_scroll" />
|
||||
<include layout="@layout/tvtypes_chips_scroll" android:id="@+id/tvtypes_chips_scroll" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
app:tint="?attr/textColor" />
|
||||
</FrameLayout>
|
||||
|
||||
<include layout="@layout/tvtypes_chips_scroll" />
|
||||
<include layout="@layout/tvtypes_chips_scroll" android:id="@+id/tvtypes_chips_scroll" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp">
|
||||
<include layout="@layout/tvtypes_chips_scroll" />
|
||||
<include layout="@layout/tvtypes_chips_scroll" android:id="@+id/tvtypes_chips_scroll" />
|
||||
<LinearLayout
|
||||
android:id="@+id/apply_btt_holder"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
|
||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/page_recyclerview"
|
||||
|
|
|
@ -1,151 +1,152 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
android:id="@+id/episode_holder_large"
|
||||
android:id="@+id/episode_holder_large"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
app:cardBackgroundColor="?attr/boxItemBackground"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
app:cardBackgroundColor="?attr/boxItemBackground"
|
||||
|
||||
android:layout_marginBottom="10dp">
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius">
|
||||
|
||||
<LinearLayout
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:padding="10dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content">
|
||||
android:id="@+id/episode_lin_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<!--app:cardCornerRadius="@dimen/roundedImageRadius"-->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="126dp"
|
||||
android:layout_height="72dp"
|
||||
android:foreground="@drawable/outline_drawable">
|
||||
android:layout_width="126dp"
|
||||
android:layout_height="72dp"
|
||||
android:foreground="@drawable/outline_drawable">
|
||||
|
||||
<ImageView
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
android:id="@+id/episode_poster"
|
||||
|
||||
android:id="@+id/episode_poster"
|
||||
tools:src="@drawable/example_poster"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/episode_poster_img_des"
|
||||
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/episode_poster_img_des" />
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@drawable/example_poster" />
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/play_button"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:contentDescription="@string/play_episode" />
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/play_episode"
|
||||
android:src="@drawable/play_button" />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:layout_marginBottom="-1.5dp"
|
||||
android:id="@+id/episode_progress"
|
||||
android:progressTint="?attr/colorPrimary"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
tools:progress="50"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_height="5dp" />
|
||||
android:id="@+id/episode_progress"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="5dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="-1.5dp"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
android:progressTint="?attr/colorPrimary"
|
||||
tools:progress="50" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginStart="15dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="start"
|
||||
style="@style/SmallBlackButton"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/filler"
|
||||
android:id="@+id/episode_filler" />
|
||||
android:id="@+id/episode_filler"
|
||||
style="@style/SmallBlackButton"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/filler" />
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:id="@+id/episode_text"
|
||||
tools:text="1. Jobless"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:id="@+id/episode_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textColor="?attr/textColor"
|
||||
android:textStyle="bold"
|
||||
tools:text="1. Jobless" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/episode_rating"
|
||||
tools:text="Rated: 8.8"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:id="@+id/episode_rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:text="Rated: 8.8" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_marginStart="-50dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginStart="-50dp">
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:id="@+id/result_episode_progress_downloaded"
|
||||
android:indeterminate="false"
|
||||
android:progressDrawable="@drawable/circular_progress_bar"
|
||||
android:background="@drawable/circle_shape"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:max="100"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:progress="0"
|
||||
android:visibility="visible" />
|
||||
android:id="@+id/result_episode_progress_downloaded"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:background="@drawable/circle_shape"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:progressDrawable="@drawable/circular_progress_bar"
|
||||
android:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:nextFocusLeft="@id/episode_poster"
|
||||
android:id="@+id/result_episode_download"
|
||||
android:id="@+id/result_episode_download"
|
||||
android:layout_width="50dp"
|
||||
|
||||
android:visibility="visible"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:padding="10dp"
|
||||
android:layout_width="50dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:contentDescription="@string/download"
|
||||
app:tint="?attr/white" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/download"
|
||||
android:nextFocusLeft="@id/episode_poster"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_baseline_play_arrow_24"
|
||||
android:visibility="visible"
|
||||
app:tint="?attr/white" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:maxLines="4"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:id="@+id/episode_descript"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:text="Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart."
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:id="@+id/episode_descript"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="4"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:text="Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart." />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
|
@ -6,5 +6,5 @@
|
|||
android:requiresFadingEdge="horizontal"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<include layout="@layout/tvtypes_chips" />
|
||||
<include layout="@layout/tvtypes_chips" android:id="@+id/tvtypes_chips" />
|
||||
</HorizontalScrollView>
|
Loading…
Reference in a new issue