more views -> viewbinding

This commit is contained in:
LagradOst 2023-07-14 02:28:49 +02:00
parent 05a0d3cd81
commit 166a21f74e
19 changed files with 412 additions and 502 deletions

View File

@ -743,6 +743,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
updateTv()
if (isTvSettings()) {
setContentView(R.layout.activity_main_tv)
} else {

View File

@ -16,14 +16,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible
import com.lagradost.cloudstream3.R
import kotlinx.android.synthetic.main.activity_easter_egg_monke.*
import java.util.*
import com.lagradost.cloudstream3.databinding.ActivityEasterEggMonkeBinding
class EasterEggMonke : AppCompatActivity() {
lateinit var binding : ActivityEasterEggMonkeBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_easter_egg_monke)
binding = ActivityEasterEggMonkeBinding.inflate(layoutInflater)
setContentView(binding.root)
val handler = Handler(mainLooper)
lateinit var runnable: Runnable
@ -32,15 +34,14 @@ class EasterEggMonke : AppCompatActivity() {
handler.postDelayed(runnable, 300)
}
handler.postDelayed(runnable, 1000)
}
private fun shower() {
val containerW = frame.width
val containerH = frame.height
var starW: Float = monke.width.toFloat()
var starH: Float = monke.height.toFloat()
val containerW = binding.frame.width
val containerH = binding.frame.height
var starW: Float = binding.monke.width.toFloat()
var starH: Float = binding.monke.height.toFloat()
val newStar = AppCompatImageView(this)
val idx = (monkeys.size * Math.random()).toInt()
@ -48,7 +49,7 @@ class EasterEggMonke : AppCompatActivity() {
newStar.isVisible = true
newStar.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
frame.addView(newStar)
binding.frame.addView(newStar)
newStar.scaleX = Math.random().toFloat() * 1.5f + newStar.scaleX
newStar.scaleY = newStar.scaleX
@ -70,7 +71,7 @@ class EasterEggMonke : AppCompatActivity() {
set.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
frame.removeView(newStar)
binding.frame.removeView(newStar)
}
})

View File

@ -12,20 +12,23 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.navigation.fragment.findNavController
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.databinding.FragmentWebviewBinding
import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.AppUtils.loadRepository
import kotlinx.android.synthetic.main.fragment_webview.*
class WebviewFragment : Fragment() {
var binding: FragmentWebviewBinding? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val url = arguments?.getString(WEBVIEW_URL) ?: "".also {
findNavController().popBackStack()
}
web_view.webViewClient = object : WebViewClient() {
binding?.webView?.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
@ -40,24 +43,28 @@ class WebviewFragment : Fragment() {
return super.shouldOverrideUrlLoading(view, request)
}
}
binding?.webView?.apply {
WebViewResolver.webViewUserAgent = settings.userAgentString
WebViewResolver.webViewUserAgent = web_view.settings.userAgentString
web_view.addJavascriptInterface(RepoApi(activity), "RepoApi")
web_view.settings.javaScriptEnabled = true
web_view.settings.userAgentString = USER_AGENT
web_view.settings.domStorageEnabled = true
addJavascriptInterface(RepoApi(activity), "RepoApi")
settings.javaScriptEnabled = true
settings.userAgentString = USER_AGENT
settings.domStorageEnabled = true
// WebView.setWebContentsDebuggingEnabled(true)
web_view.loadUrl(url)
loadUrl(url)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
val localBinding = FragmentWebviewBinding.inflate(inflater, container, false)
binding = localBinding
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_webview, container, false)
return localBinding.root//inflater.inflate(R.layout.fragment_webview, container, false)
}
companion object {
@ -70,7 +77,7 @@ class WebviewFragment : Fragment() {
private class RepoApi(val activity: FragmentActivity?) {
@JavascriptInterface
fun installRepo(repoUrl: String) {
fun installRepo(repoUrl: String) {
activity?.loadRepository(repoUrl)
}
}

View File

@ -3,18 +3,13 @@ package com.lagradost.cloudstream3.ui.download
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import kotlinx.android.synthetic.main.download_child_episode.view.*
import java.util.*
import java.util.Collections
const val DOWNLOAD_ACTION_PLAY_FILE = 0
const val DOWNLOAD_ACTION_DELETE_FILE = 1
@ -68,7 +63,7 @@ class DownloadChildAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return DownloadChildViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.download_child_episode, parent, false),
DownloadChildEpisodeBinding.inflate(LayoutInflater.from(parent.context), parent, false),
clickCallback
)
}
@ -88,17 +83,17 @@ class DownloadChildAdapter(
class DownloadChildViewHolder
constructor(
itemView: View,
val binding: DownloadChildEpisodeBinding,
private val clickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
) : RecyclerView.ViewHolder(binding.root), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton()
private val title: TextView = itemView.download_child_episode_text
/*private val title: TextView = itemView.download_child_episode_text
private val extraInfo: TextView = itemView.download_child_episode_text_extra
private val holder: CardView = itemView.download_child_episode_holder
private val progressBar: ContentLoadingProgressBar = itemView.download_child_episode_progress
private val progressBarDownload: ContentLoadingProgressBar = itemView.download_child_episode_progress_downloaded
private val downloadImage: ImageView = itemView.download_child_episode_download
private val downloadImage: ImageView = itemView.download_child_episode_download*/
private var localCard: VisualDownloadChildCached? = null
@ -107,29 +102,35 @@ class DownloadChildAdapter(
val d = card.data
val posDur = getViewPos(d.id)
if (posDur != null) {
val visualPos = posDur.fixVisual()
progressBar.max = (visualPos.duration / 1000).toInt()
progressBar.progress = (visualPos.position / 1000).toInt()
progressBar.visibility = View.VISIBLE
} else {
progressBar.visibility = View.GONE
binding.downloadChildEpisodeProgress.apply {
if (posDur != null) {
val visualPos = posDur.fixVisual()
max = (visualPos.duration / 1000).toInt()
progress = (visualPos.position / 1000).toInt()
visibility = View.VISIBLE
} else {
visibility = View.GONE
}
}
binding.downloadChildEpisodeText.apply {
text = context.getNameFull(d.name, d.episode, d.season)
isSelected = true // is needed for text repeating
}
title.text = title.context.getNameFull(d.name, d.episode, d.season)
title.isSelected = true // is needed for text repeating
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
progressBarDownload,
downloadImage,
extraInfo,
binding.downloadChildEpisodeProgressDownloaded,
binding.downloadChildEpisodeDownload,
binding.downloadChildEpisodeTextExtra,
card.data,
clickCallback
)
holder.setOnClickListener {
binding.downloadChildEpisodeHolder.setOnClickListener {
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
}
}
@ -141,9 +142,9 @@ class DownloadChildAdapter(
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
progressBarDownload,
downloadImage,
extraInfo,
binding.downloadChildEpisodeProgressDownloaded,
binding.downloadChildEpisodeDownload,
binding.downloadChildEpisodeTextExtra,
card.data,
clickCallback
)

View File

@ -5,16 +5,12 @@ import android.text.format.Formatter.formatShortFileSize
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import kotlinx.android.synthetic.main.download_header_episode.view.*
import java.util.*
data class VisualDownloadHeaderCached(
@ -66,7 +62,7 @@ class DownloadHeaderAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return DownloadHeaderViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.download_header_episode, parent, false),
DownloadHeaderEpisodeBinding.inflate(LayoutInflater.from(parent.context),parent,false),
clickCallback,
movieClickCallback
)
@ -87,20 +83,20 @@ class DownloadHeaderAdapter(
class DownloadHeaderViewHolder
constructor(
itemView: View,
val binding: DownloadHeaderEpisodeBinding,
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
private val movieClickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
) : RecyclerView.ViewHolder(binding.root), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton()
private val poster: ImageView? = itemView.download_header_poster
/*private val poster: ImageView? = itemView.download_header_poster
private val title: TextView = itemView.download_header_title
private val extraInfo: TextView = itemView.download_header_info
private val holder: CardView = itemView.episode_holder
private val downloadBar: ContentLoadingProgressBar = itemView.download_header_progress_downloaded
private val downloadImage: ImageView = itemView.download_header_episode_download
private val normalImage: ImageView = itemView.download_header_goto_child
private val normalImage: ImageView = itemView.download_header_goto_child*/
private var localCard: VisualDownloadHeaderCached? = null
@SuppressLint("SetTextI18n")
@ -108,19 +104,24 @@ class DownloadHeaderAdapter(
localCard = card
val d = card.data
poster?.setImage(d.poster)
poster?.setOnClickListener {
clickCallback.invoke(DownloadHeaderClickEvent(1, d))
binding.downloadHeaderPoster.apply {
setImage(d.poster)
setOnClickListener {
clickCallback.invoke(DownloadHeaderClickEvent(1, d))
}
}
title.text = d.name
binding.apply {
binding.downloadHeaderTitle.text = d.name
val mbString = formatShortFileSize(itemView.context, card.totalBytes)
//val isMovie = d.type.isMovieType()
if (card.child != null) {
downloadBar.visibility = View.VISIBLE
downloadImage.visibility = View.VISIBLE
normalImage.visibility = View.GONE
downloadHeaderProgressDownloaded.visibility = View.VISIBLE
downloadHeaderEpisodeDownload.visibility = View.VISIBLE
binding.downloadHeaderGotoChild.visibility = View.GONE
/*setUpButton(
card.currentBytes,
card.totalBytes,
@ -131,34 +132,35 @@ class DownloadHeaderAdapter(
movieClickCallback
)*/
holder.setOnClickListener {
episodeHolder.setOnClickListener {
movieClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child))
}
} else {
downloadBar.visibility = View.GONE
downloadImage.visibility = View.GONE
normalImage.visibility = View.VISIBLE
downloadHeaderProgressDownloaded.visibility = View.GONE
downloadHeaderEpisodeDownload.visibility = View.GONE
binding.downloadHeaderGotoChild.visibility = View.VISIBLE
try {
extraInfo.text =
extraInfo.context.getString(R.string.extra_info_format).format(
downloadHeaderInfo.text =
downloadHeaderInfo.context.getString(R.string.extra_info_format).format(
card.totalDownloads,
if (card.totalDownloads == 1) extraInfo.context.getString(R.string.episode) else extraInfo.context.getString(
if (card.totalDownloads == 1) downloadHeaderInfo.context.getString(R.string.episode) else downloadHeaderInfo.context.getString(
R.string.episodes
),
mbString
)
} catch (t : Throwable) {
// you probably formatted incorrectly
extraInfo.text = "Error"
downloadHeaderInfo.text = "Error"
logError(t)
}
holder.setOnClickListener {
episodeHolder.setOnClickListener {
clickCallback.invoke(DownloadHeaderClickEvent(0, d))
}
}
}
}
override fun reattachDownloadButton() {
@ -168,9 +170,9 @@ class DownloadHeaderAdapter(
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
downloadBar,
downloadImage,
extraInfo,
binding.downloadHeaderProgressDownloaded,
binding.downloadHeaderEpisodeDownload,
binding.downloadHeaderInfo,
card.child,
movieClickCallback
)

View File

@ -3,49 +3,24 @@ package com.lagradost.cloudstream3.ui.home
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.ChangeBounds
import androidx.transition.TransitionManager
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable
import com.lagradost.cloudstream3.APIHolder.getId
import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity
import com.lagradost.cloudstream3.HomePageList
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.result.LinearListLayout
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbarView
import kotlinx.android.synthetic.main.activity_main_tv.*
import kotlinx.android.synthetic.main.activity_main_tv.view.*
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.android.synthetic.main.fragment_home_head_tv.*
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.*
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_preview
import kotlinx.android.synthetic.main.fragment_home_head_tv.view.home_preview_viewpager
import kotlinx.android.synthetic.main.homepage_parent.view.*
class LoadClickCallback(

View File

@ -5,15 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.ListPopupWindow.MATCH_PARENT
import android.widget.RelativeLayout
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.loading_poster_dynamic.view.*
import kotlin.math.roundToInt
import kotlin.math.sqrt
class LoadingPosterAdapter(context: Context, private val itemCount: Int) :
BaseAdapter() {

View File

@ -97,12 +97,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
protected var isShowing = false
protected var isLocked = false
//private var episodes: List<Any> = listOf()
protected fun setEpisodes(ep: List<Any>) {
//hasEpisodes = ep.size > 1 // if has 2 episodes or more because you dont want to switch to your current episode
//(player_episode_list?.adapter as? PlayerEpisodeAdapter?)?.updateList(ep)
}
protected var hasEpisodes = false
private set
//protected val hasEpisodes

View File

@ -163,7 +163,7 @@ class GeneratorPlayer : FullScreenPlayer() {
currentSelectedLink = link
currentMeta = viewModel.getMeta()
nextMeta = viewModel.getNextMeta()
setEpisodes(viewModel.getAllMeta() ?: emptyList())
// setEpisodes(viewModel.getAllMeta() ?: emptyList())
isActive = true
setPlayerDimen(null)
setTitle()

View File

@ -1,158 +0,0 @@
package com.lagradost.cloudstream3.ui.player
import android.annotation.SuppressLint
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.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.ui.result.getDisplayPosition
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import kotlinx.android.synthetic.main.player_episodes_large.view.episode_holder_large
import kotlinx.android.synthetic.main.player_episodes_large.view.episode_progress
import kotlinx.android.synthetic.main.player_episodes_small.view.episode_holder
import kotlinx.android.synthetic.main.result_episode_large.view.*
data class PlayerEpisodeClickEvent(val action: Int, val data: Any)
class PlayerEpisodeAdapter(
private val items: MutableList<Any> = mutableListOf(),
private val clickCallback: (PlayerEpisodeClickEvent) -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return PlayerEpisodeCardViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.player_episodes, parent, false),
clickCallback,
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
println("HOLDER $holder $position")
when (holder) {
is PlayerEpisodeCardViewHolder -> {
holder.bind(items[position])
}
}
}
override fun getItemCount(): Int {
return items.size
}
fun updateList(newList: List<Any>) {
println("Updated list $newList")
val diffResult = DiffUtil.calculateDiff(EpisodeDiffCallback(this.items, newList))
items.clear()
items.addAll(newList)
diffResult.dispatchUpdatesTo(this)
}
class PlayerEpisodeCardViewHolder
constructor(
itemView: View,
private val clickCallback: (PlayerEpisodeClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView) {
@SuppressLint("SetTextI18n")
fun bind(card: Any) {
if (card is ResultEpisode) {
val (parentView, otherView) = if (card.poster == null) {
itemView.episode_holder to itemView.episode_holder_large
} else {
itemView.episode_holder_large to itemView.episode_holder
}
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
parentView.isVisible = true
otherView.isVisible = false
episodeText?.apply {
val name =
if (card.name == null) "${context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
text = name
isSelected = true
}
episodeFiller?.isVisible = card.isFiller == true
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(PlayerEpisodeClickEvent(ACTION_SHOW_DESCRIPTION, card))
//}
}
parentView.setOnClickListener {
clickCallback.invoke(PlayerEpisodeClickEvent(0, card))
}
if (isTrueTvSettings()) {
parentView.isFocusable = true
parentView.isFocusableInTouchMode = true
parentView.touchscreenBlocksFocus = false
}
}
}
}
}
class EpisodeDiffCallback(
private val oldList: List<Any>,
private val newList: List<Any>
) :
DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val a = oldList[oldItemPosition]
val b = newList[newItemPosition]
return if (a is ResultEpisode && b is ResultEpisode) {
a.id == b.id
} else {
a == b
}
}
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition] == newList[newItemPosition]
}

View File

@ -4,16 +4,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import androidx.viewbinding.ViewBinding
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.databinding.SearchResultGridBinding
import com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding
import com.lagradost.cloudstream3.ui.AutofitRecyclerView
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.UIHelper.IsBottomLayout
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.search_result_compact.view.*
import kotlin.math.roundToInt
/** Click */
@ -39,10 +38,23 @@ class SearchAdapter(
var hasNext: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layout =
if (parent.context.IsBottomLayout()) R.layout.search_result_grid_expanded else R.layout.search_result_grid
if (parent.context.IsBottomLayout()) SearchResultGridExpandedBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
) else SearchResultGridBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
) //R.layout.search_result_grid_expanded else R.layout.search_result_grid
return CardViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false),
layout,
clickCallback,
resView
)
@ -73,12 +85,11 @@ class SearchAdapter(
class CardViewHolder
constructor(
itemView: View,
val binding: ViewBinding,
private val clickCallback: (SearchClickCallback) -> Unit,
resView: AutofitRecyclerView
) :
RecyclerView.ViewHolder(itemView) {
private val cardView: ImageView = itemView.imageView
RecyclerView.ViewHolder(binding.root) {
private val compactView = false//itemView.context.getGridIsCompact()
private val coverHeight: Int =
@ -86,7 +97,7 @@ class SearchAdapter(
fun bind(card: SearchResponse, position: Int) {
if (!compactView) {
cardView.apply {
binding.root.apply {
layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
coverHeight

View File

@ -104,6 +104,7 @@ class SearchFragment : Fragment() {
val layout = if (isTvSettings()) R.layout.fragment_search_tv else R.layout.fragment_search
val root = inflater.inflate(layout, container, false)
// TODO TRYCATCH
binding = FragmentSearchBinding.bind(root)
return root

View File

@ -15,6 +15,9 @@ import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.AccountManagmentBinding
import com.lagradost.cloudstream3.databinding.AccountSwitchBinding
import com.lagradost.cloudstream3.databinding.AddAccountInputBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi
@ -31,9 +34,6 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import kotlinx.android.synthetic.main.account_managment.*
import kotlinx.android.synthetic.main.account_switch.*
import kotlinx.android.synthetic.main.add_account_input.*
class SettingsAccount : PreferenceFragmentCompat() {
companion object {
@ -43,15 +43,18 @@ class SettingsAccount : PreferenceFragmentCompat() {
api: AccountManager,
info: AuthAPI.LoginInfo
) {
if (activity == null) return
val binding: AccountManagmentBinding =
AccountManagmentBinding.inflate(activity.layoutInflater, null, false)
val builder =
AlertDialog.Builder(activity ?: return, R.style.AlertDialogCustom)
.setView(R.layout.account_managment)
AlertDialog.Builder(activity, R.style.AlertDialogCustom)
.setView(binding.root)
val dialog = builder.show()
dialog.account_main_profile_picture_holder?.isVisible =
dialog.account_main_profile_picture?.setImage(info.profilePicture) == true
binding.accountMainProfilePictureHolder.isVisible =
binding.accountMainProfilePicture.setImage(info.profilePicture)
dialog.account_logout?.setOnClickListener {
binding.accountLogout.setOnClickListener {
api.logOut()
dialog.dismissSafe(activity)
}
@ -60,26 +63,28 @@ class SettingsAccount : PreferenceFragmentCompat() {
dialog.findViewById<TextView>(R.id.account_name)?.text = it
}
dialog.account_site?.text = api.name
dialog.account_switch_account?.setOnClickListener {
binding.accountSite.text = api.name
binding.accountSwitchAccount.setOnClickListener {
dialog.dismissSafe(activity)
showAccountSwitch(activity, api)
}
if (isTvSettings()) {
dialog.account_switch_account?.requestFocus()
binding.accountSwitchAccount.requestFocus()
}
}
fun showAccountSwitch(activity: FragmentActivity, api: AccountManager) {
private fun showAccountSwitch(activity: FragmentActivity, api: AccountManager) {
val accounts = api.getAccounts() ?: return
val binding: AccountSwitchBinding =
AccountSwitchBinding.inflate(activity.layoutInflater, null, false)
val builder =
AlertDialog.Builder(activity, R.style.AlertDialogCustom)
.setView(R.layout.account_switch)
.setView(binding.root)
val dialog = builder.show()
dialog.account_add?.setOnClickListener {
binding.accountAdd.setOnClickListener {
addAccount(activity, api)
dialog?.dismissSafe(activity)
}
@ -111,17 +116,21 @@ class SettingsAccount : PreferenceFragmentCompat() {
is OAuth2API -> {
api.authenticate(activity)
}
is InAppAuthAPI -> {
if (activity == null) return
val binding: AddAccountInputBinding =
AddAccountInputBinding.inflate(activity.layoutInflater, null, false)
val builder =
AlertDialog.Builder(activity ?: return, R.style.AlertDialogCustom)
.setView(R.layout.add_account_input)
AlertDialog.Builder(activity, R.style.AlertDialogCustom)
.setView(binding.root)
val dialog = builder.show()
val visibilityMap = mapOf(
dialog.login_email_input to api.requiresEmail,
dialog.login_password_input to api.requiresPassword,
dialog.login_server_input to api.requiresServer,
dialog.login_username_input to api.requiresUsername
val visibilityMap = listOf(
binding.loginEmailInput to api.requiresEmail,
binding.loginPasswordInput to api.requiresPassword,
binding.loginServerInput to api.requiresServer,
binding.loginUsernameInput to api.requiresUsername
)
if (isTvSettings()) {
@ -145,12 +154,12 @@ class SettingsAccount : PreferenceFragmentCompat() {
}
}
dialog.login_email_input?.isVisible = api.requiresEmail
dialog.login_password_input?.isVisible = api.requiresPassword
dialog.login_server_input?.isVisible = api.requiresServer
dialog.login_username_input?.isVisible = api.requiresUsername
dialog.create_account?.isGone = api.createAccountUrl.isNullOrBlank()
dialog.create_account?.setOnClickListener {
binding.loginEmailInput.isVisible = api.requiresEmail
binding.loginPasswordInput.isVisible = api.requiresPassword
binding.loginServerInput.isVisible = api.requiresServer
binding.loginUsernameInput.isVisible = api.requiresUsername
binding.createAccount.isGone = api.createAccountUrl.isNullOrBlank()
binding.createAccount.setOnClickListener {
openBrowser(
api.createAccountUrl ?: return@setOnClickListener,
activity
@ -159,43 +168,43 @@ class SettingsAccount : PreferenceFragmentCompat() {
}
val displayedItems = listOf(
dialog.login_username_input,
dialog.login_email_input,
dialog.login_server_input,
dialog.login_password_input
binding.loginUsernameInput,
binding.loginEmailInput,
binding.loginServerInput,
binding.loginPasswordInput
).filter { it.isVisible }
displayedItems.foldRight(displayedItems.firstOrNull()) { item, previous ->
item?.id?.let { previous?.nextFocusDownId = it }
previous?.id?.let { item?.nextFocusUpId = it }
item.id.let { previous?.nextFocusDownId = it }
previous?.id?.let { item.nextFocusUpId = it }
item
}
displayedItems.firstOrNull()?.let {
dialog.create_account?.nextFocusDownId = it.id
it.nextFocusUpId = dialog.create_account.id
binding.createAccount.nextFocusDownId = it.id
it.nextFocusUpId = binding.createAccount.id
}
dialog.apply_btt?.id?.let {
binding.applyBtt.id.let {
displayedItems.lastOrNull()?.nextFocusDownId = it
}
dialog.text1?.text = api.name
binding.text1.text = api.name
if (api.storesPasswordInPlainText) {
api.getLatestLoginData()?.let { data ->
dialog.login_email_input?.setText(data.email ?: "")
dialog.login_server_input?.setText(data.server ?: "")
dialog.login_username_input?.setText(data.username ?: "")
dialog.login_password_input?.setText(data.password ?: "")
binding.loginEmailInput.setText(data.email ?: "")
binding.loginServerInput.setText(data.server ?: "")
binding.loginUsernameInput.setText(data.username ?: "")
binding.loginPasswordInput.setText(data.password ?: "")
}
}
dialog.apply_btt?.setOnClickListener {
binding.applyBtt.setOnClickListener {
val loginData = InAppAuthAPI.LoginData(
username = if (api.requiresUsername) dialog.login_username_input?.text?.toString() else null,
password = if (api.requiresPassword) dialog.login_password_input?.text?.toString() else null,
email = if (api.requiresEmail) dialog.login_email_input?.text?.toString() else null,
server = if (api.requiresServer) dialog.login_server_input?.text?.toString() else null,
username = if (api.requiresUsername) binding.loginUsernameInput.text?.toString() else null,
password = if (api.requiresPassword) binding.loginPasswordInput.text?.toString() else null,
email = if (api.requiresEmail) binding.loginEmailInput.text?.toString() else null,
server = if (api.requiresServer) binding.loginServerInput.text?.toString() else null,
)
ioSafe {
val isSuccessful = try {
@ -220,10 +229,11 @@ class SettingsAccount : PreferenceFragmentCompat() {
}
dialog.dismissSafe(activity)
}
dialog.cancel_btt?.setOnClickListener {
binding.cancelBtt.setOnClickListener {
dialog.dismissSafe(activity)
}
}
else -> {
throw NotImplementedError("You are trying to add an account that has an unknown login method")
}

View File

@ -14,7 +14,9 @@ import androidx.fragment.app.Fragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.google.android.material.appbar.MaterialToolbar
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.MainSettingsBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers
import com.lagradost.cloudstream3.ui.home.HomeFragment
@ -22,16 +24,14 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.main_settings.*
import kotlinx.android.synthetic.main.standard_toolbar.*
import java.io.File
class SettingsFragment : Fragment() {
companion object {
var beneneCount = 0
private var isTv : Boolean = false
private var isTrueTv : Boolean = false
private var isTv: Boolean = false
private var isTrueTv: Boolean = false
fun PreferenceFragmentCompat?.getPref(id: Int): Preference? {
if (this == null) return null
@ -55,26 +55,30 @@ class SettingsFragment : Fragment() {
fun Fragment?.setUpToolbar(title: String) {
if (this == null) return
settings_toolbar?.apply {
val settingsToolbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar) ?: return
settingsToolbar.apply {
setTitle(title)
setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
setNavigationOnClickListener {
activity?.onBackPressed()
}
}
fixPaddingStatusbar(settings_toolbar)
fixPaddingStatusbar(settingsToolbar)
}
fun Fragment?.setUpToolbar(@StringRes title: Int) {
if (this == null) return
settings_toolbar?.apply {
val settingsToolbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar) ?: return
settingsToolbar.apply {
setTitle(title)
setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
setNavigationOnClickListener {
activity?.onBackPressed()
}
}
fixPaddingStatusbar(settings_toolbar)
fixPaddingStatusbar(settingsToolbar)
}
fun getFolderSize(dir: File): Long {
@ -139,12 +143,21 @@ class SettingsFragment : Fragment() {
}
}
override fun onDestroyView() {
binding = null
super.onDestroyView()
}
var binding: MainSettingsBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return inflater.inflate(R.layout.main_settings, container, false)
): View {
val localBinding = MainSettingsBinding.inflate(inflater, container, false)
binding = localBinding
return localBinding.root
//return inflater.inflate(R.layout.main_settings, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -157,36 +170,34 @@ class SettingsFragment : Fragment() {
for (syncApi in accountManagers) {
val login = syncApi.loginInfo()
val pic = login?.profilePicture ?: continue
if (settings_profile_pic?.setImage(
if (binding?.settingsProfilePic?.setImage(
pic,
errorImageDrawable = HomeFragment.errorProfilePic
) == true
) {
settings_profile_text?.text = login.name
settings_profile?.isVisible = true
binding?.settingsProfileText?.text = login.name
binding?.settingsProfile?.isVisible = true
break
}
}
listOf(
Pair(settings_general, R.id.action_navigation_settings_to_navigation_settings_general),
Pair(settings_player, R.id.action_navigation_settings_to_navigation_settings_player),
Pair(settings_credits, R.id.action_navigation_settings_to_navigation_settings_account),
Pair(settings_ui, R.id.action_navigation_settings_to_navigation_settings_ui),
Pair(settings_providers, R.id.action_navigation_settings_to_navigation_settings_providers),
Pair(settings_updates, R.id.action_navigation_settings_to_navigation_settings_updates),
Pair(
settings_extensions,
R.id.action_navigation_settings_to_navigation_settings_extensions
),
).forEach { (view, navigationId) ->
view?.apply {
setOnClickListener {
navigate(navigationId)
}
if (isTrueTv) {
isFocusable = true
isFocusableInTouchMode = true
binding?.apply {
listOf(
settingsGeneral to R.id.action_navigation_settings_to_navigation_settings_general,
settingsPlayer to R.id.action_navigation_settings_to_navigation_settings_player,
settingsCredits to R.id.action_navigation_settings_to_navigation_settings_account,
settingsUi to R.id.action_navigation_settings_to_navigation_settings_ui,
settingsProviders to R.id.action_navigation_settings_to_navigation_settings_providers,
settingsUpdates to R.id.action_navigation_settings_to_navigation_settings_updates,
settingsExtensions to R.id.action_navigation_settings_to_navigation_settings_extensions,
).forEach { (view, navigationId) ->
view.apply {
setOnClickListener {
navigate(navigationId)
}
if (isTrueTv) {
isFocusable = true
isFocusableInTouchMode = true
}
}
}
}

View File

@ -22,6 +22,8 @@ import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.databinding.AddRemoveSitesBinding
import com.lagradost.cloudstream3.databinding.AddSiteInputBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient
@ -38,8 +40,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
import kotlinx.android.synthetic.main.add_remove_sites.*
import kotlinx.android.synthetic.main.add_site_input.*
import java.io.File
fun getCurrentLocale(context: Context): String {
@ -197,18 +197,20 @@ class SettingsGeneral : PreferenceFragmentCompat() {
{}) { selection ->
val provider = providers.getOrNull(selection) ?: return@showDialog
val binding : AddSiteInputBinding = AddSiteInputBinding.inflate(layoutInflater,null,false)
val builder =
AlertDialog.Builder(context ?: return@showDialog, R.style.AlertDialogCustom)
.setView(R.layout.add_site_input)
.setView(binding.root)
val dialog = builder.create()
dialog.show()
dialog.text2?.text = provider.name
dialog.apply_btt?.setOnClickListener {
val name = dialog.site_name_input?.text?.toString()
val url = dialog.site_url_input?.text?.toString()
val lang = dialog.site_lang_input?.text?.toString()
binding.text2.text = provider.name
binding.applyBtt.setOnClickListener {
val name = binding.siteNameInput.text?.toString()
val url = binding.siteUrlInput.text?.toString()
val lang = binding.siteLangInput.text?.toString()
val realLang = if (lang.isNullOrBlank()) provider.lang else lang
if (url.isNullOrBlank() || name.isNullOrBlank() || realLang.length != 2) {
showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT)
@ -222,7 +224,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
dialog.dismissSafe(activity)
}
dialog.cancel_btt?.setOnClickListener {
binding.cancelBtt.setOnClickListener {
dialog.dismissSafe(activity)
}
}
@ -242,18 +244,19 @@ class SettingsGeneral : PreferenceFragmentCompat() {
}
fun showAddOrDelete() {
val binding : AddRemoveSitesBinding = AddRemoveSitesBinding.inflate(layoutInflater,null,false)
val builder =
AlertDialog.Builder(context ?: return, R.style.AlertDialogCustom)
.setView(R.layout.add_remove_sites)
.setView(binding.root)
val dialog = builder.create()
dialog.show()
dialog.add_site?.setOnClickListener {
binding.addSite.setOnClickListener {
showAdd()
dialog.dismissSafe(activity)
}
dialog.remove_site?.setOnClickListener {
binding.removeSite.setOnClickListener {
showDelete()
dialog.dismissSafe(activity)
}

View File

@ -13,6 +13,7 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.LogcatBinding
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
@ -25,7 +26,6 @@ import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.logcat.*
import okhttp3.internal.closeQuietly
import java.io.BufferedReader
import java.io.InputStreamReader
@ -60,7 +60,9 @@ class SettingsUpdates : PreferenceFragmentCompat() {
getPref(R.string.show_logcat_key)?.setOnPreferenceClickListener { pref ->
val builder =
AlertDialog.Builder(pref.context, R.style.AlertDialogCustom)
.setView(R.layout.logcat)
val binding = LogcatBinding.inflate(layoutInflater,null,false )
builder.setView(binding.root)
val dialog = builder.create()
dialog.show()
@ -81,9 +83,9 @@ class SettingsUpdates : PreferenceFragmentCompat() {
}
val text = log.toString()
dialog.text1?.text = text
binding.text1.text = text
dialog.copy_btt?.setOnClickListener {
binding.copyBtt.setOnClickListener {
// Can crash on too much text
try {
val serviceClipboard =
@ -96,11 +98,11 @@ class SettingsUpdates : PreferenceFragmentCompat() {
showToast(activity, R.string.clipboard_too_large)
}
}
dialog.clear_btt?.setOnClickListener {
binding.clearBtt.setOnClickListener {
Runtime.getRuntime().exec("logcat -c")
dialog.dismissSafe(activity)
}
dialog.save_btt?.setOnClickListener {
binding.saveBtt.setOnClickListener {
var fileStream: OutputStream? = null
try {
fileStream =
@ -119,7 +121,7 @@ class SettingsUpdates : PreferenceFragmentCompat() {
dialog.dismissSafe(activity)
}
}
dialog.close_btt?.setOnClickListener {
binding.closeBtt.setOnClickListener {
dialog.dismissSafe(activity)
}
return@setOnPreferenceClickListener true

View File

@ -18,6 +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.databinding.AddRepoInputBinding
import com.lagradost.cloudstream3.databinding.FragmentExtensionsBinding
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.mvvm.observeNullable
import com.lagradost.cloudstream3.plugins.RepositoryManager
@ -30,16 +32,22 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.widget.LinearRecycleViewLayoutManager
import kotlinx.android.synthetic.main.add_repo_input.*
import kotlinx.android.synthetic.main.fragment_extensions.*
class ExtensionsFragment : Fragment() {
var binding: FragmentExtensionsBinding? = null
override fun onDestroyView() {
binding = null
super.onDestroyView()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return inflater.inflate(R.layout.fragment_extensions, container, false)
): View {
val localBinding = FragmentExtensionsBinding.inflate(inflater, container, false)
binding = localBinding
return localBinding.root//inflater.inflate(R.layout.fragment_extensions, container, false)
}
private fun View.setLayoutWidth(weight: Int) {
@ -74,7 +82,7 @@ class ExtensionsFragment : Fragment() {
setUpToolbar(R.string.extensions)
repo_recycler_view?.adapter = RepoAdapter(false, {
binding?.repoRecyclerView?.adapter = RepoAdapter(false, {
findNavController().navigate(
R.id.navigation_settings_extensions_to_navigation_settings_plugins,
PluginsFragment.newInstance(
@ -113,12 +121,12 @@ class ExtensionsFragment : Fragment() {
})
observe(extensionViewModel.repositories) {
repo_recycler_view?.isVisible = it.isNotEmpty()
blank_repo_screen?.isVisible = it.isEmpty()
(repo_recycler_view?.adapter as? RepoAdapter)?.updateList(it)
binding?.repoRecyclerView?.isVisible = it.isNotEmpty()
binding?.blankRepoScreen?.isVisible = it.isEmpty()
(binding?.repoRecyclerView?.adapter as? RepoAdapter)?.updateList(it)
}
repo_recycler_view?.apply {
binding?.repoRecyclerView?.apply {
context?.let { ctx ->
layoutManager = LinearRecycleViewLayoutManager(ctx, nextFocusUpId, nextFocusDownId)
}
@ -140,28 +148,30 @@ class ExtensionsFragment : Fragment() {
// }
observeNullable(extensionViewModel.pluginStats) { value ->
if (value == null) {
plugin_storage_appbar?.isVisible = false
binding?.apply {
if (value == null) {
pluginStorageAppbar.isVisible = false
return@observeNullable
}
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)
pluginStorageAppbar.isVisible = true
if (value.total == 0) {
pluginDownload.setLayoutWidth(1)
pluginDisabled.setLayoutWidth(0)
pluginNotDownloaded.setLayoutWidth(0)
} else {
pluginDownload.setLayoutWidth(value.downloaded)
pluginDisabled.setLayoutWidth(value.disabled)
pluginNotDownloaded.setLayoutWidth(value.notDownloaded)
}
pluginNotDownloadedTxt.setText(value.notDownloadedText)
pluginDisabledTxt.setText(value.disabledText)
pluginDownloadTxt.setText(value.downloadedText)
}
plugin_not_downloaded_txt.setText(value.notDownloadedText)
plugin_disabled_txt.setText(value.disabledText)
plugin_download_txt.setText(value.downloadedText)
}
plugin_storage_appbar?.setOnClickListener {
binding?.pluginStorageAppbar?.setOnClickListener {
findNavController().navigate(
R.id.navigation_settings_extensions_to_navigation_settings_plugins,
PluginsFragment.newInstance(
@ -173,16 +183,18 @@ class ExtensionsFragment : Fragment() {
}
val addRepositoryClick = View.OnClickListener {
val ctx = context ?: return@OnClickListener
val binding = AddRepoInputBinding.inflate(LayoutInflater.from(ctx), null, false)
val builder =
AlertDialog.Builder(context ?: return@OnClickListener, R.style.AlertDialogCustom)
.setView(R.layout.add_repo_input)
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
.setView(binding.root)
val dialog = builder.create()
dialog.show()
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?)?.primaryClip?.getItemAt(
0
)?.text?.toString()?.let { copy ->
dialog.repo_url_input?.setText(copy)
binding.repoUrlInput.setText(copy)
}
// dialog.list_repositories?.setOnClickListener {
@ -192,10 +204,10 @@ class ExtensionsFragment : Fragment() {
// }
// dialog.text2?.text = provider.name
dialog.apply_btt?.setOnClickListener secondListener@{
val name = dialog.repo_name_input?.text?.toString()
binding.applyBtt.setOnClickListener secondListener@{
val name = binding.repoNameInput.text?.toString()
ioSafe {
val url = dialog.repo_url_input?.text?.toString()
val url = binding.repoUrlInput.text?.toString()
?.let { it1 -> RepositoryManager.parseRepoUrl(it1) }
if (url.isNullOrBlank()) {
main {
@ -214,22 +226,23 @@ class ExtensionsFragment : Fragment() {
}
dialog.dismissSafe(activity)
}
dialog.cancel_btt?.setOnClickListener {
binding.cancelBtt.setOnClickListener {
dialog.dismissSafe(activity)
}
}
val isTv = isTrueTvSettings()
add_repo_button?.isGone = isTv
add_repo_button_imageview_holder?.isVisible = isTv
binding?.apply {
addRepoButton.isGone = isTv
addRepoButtonImageviewHolder.isVisible = isTv
// Band-aid for Fire TV
plugin_storage_appbar?.isFocusableInTouchMode = isTv
add_repo_button_imageview?.isFocusableInTouchMode = isTv
add_repo_button?.setOnClickListener(addRepositoryClick)
add_repo_button_imageview?.setOnClickListener(addRepositoryClick)
// Band-aid for Fire TV
pluginStorageAppbar.isFocusableInTouchMode = isTv
addRepoButtonImageview.isFocusableInTouchMode = isTv
addRepoButton.setOnClickListener(addRepositoryClick)
addRepoButtonImageview.setOnClickListener(addRepositoryClick)
}
reloadRepositories()
}
}

View File

@ -1,14 +1,15 @@
package com.lagradost.cloudstream3.ui.settings.extensions
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import kotlinx.android.synthetic.main.repository_item.view.*
class RepoAdapter(
val isSetup: Boolean,
@ -20,9 +21,17 @@ class RepoAdapter(
private val repositories: MutableList<RepositoryData> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layout = if(isTrueTvSettings()) R.layout.repository_item_tv else R.layout.repository_item
val layout = if (isTrueTvSettings()) RepositoryItemTvBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
) else RepositoryItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
) //R.layout.repository_item_tv else R.layout.repository_item
return RepoViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false)
layout
)
}
@ -57,30 +66,57 @@ class RepoAdapter(
diffResult.dispatchUpdatesTo(this)
}
inner class RepoViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
inner class RepoViewHolder(
val binding: ViewBinding
) :
RecyclerView.ViewHolder(binding.root) {
fun bind(
repositoryData: RepositoryData
) {
val isPrebuilt = PREBUILT_REPOSITORIES.contains(repositoryData)
val drawable =
if (isSetup) R.drawable.netflix_download else R.drawable.ic_baseline_delete_outline_24
when (binding) {
is RepositoryItemTvBinding -> {
binding.apply {
// Only shows icon if on setup or if it isn't a prebuilt repo.
// No delete buttons on prebuilt repos.
if (!isPrebuilt || isSetup) {
actionButton.setImageResource(drawable)
}
// Only shows icon if on setup or if it isn't a prebuilt repo.
// No delete buttons on prebuilt repos.
if (!isPrebuilt || isSetup) {
itemView.action_button?.setImageResource(drawable)
}
actionButton.setOnClickListener {
imageClickCallback(repositoryData)
}
itemView.action_button?.setOnClickListener {
imageClickCallback(repositoryData)
}
repositoryItemRoot.setOnClickListener {
clickCallback(repositoryData)
}
mainText.text = repositoryData.name
subText.text = repositoryData.url
}
}
itemView.repository_item_root?.setOnClickListener {
clickCallback(repositoryData)
is RepositoryItemBinding -> {
binding.apply {
// Only shows icon if on setup or if it isn't a prebuilt repo.
// No delete buttons on prebuilt repos.
if (!isPrebuilt || isSetup) {
actionButton.setImageResource(drawable)
}
actionButton.setOnClickListener {
imageClickCallback(repositoryData)
}
repositoryItemRoot.setOnClickListener {
clickCallback(repositoryData)
}
mainText.text = repositoryData.name
subText.text = repositoryData.url
}
}
}
itemView.main_text?.text = repositoryData.name
itemView.sub_text?.text = repositoryData.url
}
}
}

View File

@ -1,97 +1,105 @@
package com.lagradost.cloudstream3.ui.settings.testing
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.FragmentTestingBinding
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.mvvm.observeNullable
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import kotlinx.android.synthetic.main.fragment_testing.*
import kotlinx.android.synthetic.main.view_test.*
class TestFragment : Fragment() {
private val testViewModel: TestViewModel by activityViewModels()
var binding: FragmentTestingBinding? = null
override fun onDestroyView() {
binding = null
super.onDestroyView()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setUpToolbar(R.string.category_provider_test)
super.onViewCreated(view, savedInstanceState)
provider_test_recycler_view?.adapter = TestResultAdapter(
mutableListOf()
)
binding?.apply {
providerTestRecyclerView.adapter = TestResultAdapter(
mutableListOf()
)
testViewModel.init()
if (testViewModel.isRunningTest) {
provider_test?.setState(TestView.TestState.Running)
}
observe(testViewModel.providerProgress) { (passed, failed, total) ->
provider_test?.setProgress(passed, failed, total)
}
observeNullable(testViewModel.providerResults) {
normalSafeApiCall {
val newItems = it.sortedBy { api -> api.first.name }
(provider_test_recycler_view?.adapter as? TestResultAdapter)?.updateList(
newItems
)
testViewModel.init()
if (testViewModel.isRunningTest) {
providerTest.setState(TestView.TestState.Running)
}
}
provider_test?.setOnPlayButtonListener { state ->
when (state) {
TestView.TestState.Stopped -> testViewModel.stopTest()
TestView.TestState.Running -> testViewModel.startTest()
TestView.TestState.None -> testViewModel.startTest()
observe(testViewModel.providerProgress) { (passed, failed, total) ->
providerTest.setProgress(passed, failed, total)
}
}
if (isTrueTvSettings()) {
tests_play_pause?.isFocusableInTouchMode = true
tests_play_pause?.requestFocus()
}
provider_test?.playPauseButton?.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
provider_test_appbar?.setExpanded(true, true)
observeNullable(testViewModel.providerResults) {
normalSafeApiCall {
val newItems = it.sortedBy { api -> api.first.name }
(providerTestRecyclerView.adapter as? TestResultAdapter)?.updateList(
newItems
)
}
}
providerTest.setOnPlayButtonListener { state ->
when (state) {
TestView.TestState.Stopped -> testViewModel.stopTest()
TestView.TestState.Running -> testViewModel.startTest()
TestView.TestState.None -> testViewModel.startTest()
}
}
}
fun focusRecyclerView() {
// Hack to make it possible to focus the recyclerview.
if (isTrueTvSettings()) {
provider_test_recycler_view?.requestFocus()
provider_test_appbar?.setExpanded(false, true)
providerTest.playPauseButton?.isFocusableInTouchMode = true
providerTest.playPauseButton?.requestFocus()
}
}
provider_test?.setOnMainClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.All)
focusRecyclerView()
}
provider_test?.setOnFailedClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Failed)
focusRecyclerView()
}
provider_test?.setOnPassedClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Passed)
focusRecyclerView()
providerTest.playPauseButton?.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
providerTestAppbar.setExpanded(true, true)
}
}
fun focusRecyclerView() {
// Hack to make it possible to focus the recyclerview.
if (isTrueTvSettings()) {
providerTestRecyclerView.requestFocus()
providerTestAppbar.setExpanded(false, true)
}
}
providerTest.setOnMainClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.All)
focusRecyclerView()
}
providerTest.setOnFailedClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Failed)
focusRecyclerView()
}
providerTest.setOnPassedClick {
testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Passed)
focusRecyclerView()
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_testing, container, false)
): View {
val localBinding = FragmentTestingBinding.inflate(inflater, container, false)
binding = localBinding
return localBinding.root//inflater.inflate(R.layout.fragment_testing, container, false)
}
}