more views + MainActivity viewbindings

This commit is contained in:
LagradOst 2023-07-14 21:43:46 +02:00
parent 166a21f74e
commit 647e91bc4b
11 changed files with 237 additions and 128 deletions

View File

@ -208,7 +208,7 @@ dependencies {
implementation("com.github.discord:OverlappingPanels:0.1.3")
// debugImplementation because LeakCanary should only run in debug builds.
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7")
// for shimmer when loading
implementation("com.facebook.shimmer:shimmer:0.5.0")
@ -228,7 +228,7 @@ dependencies {
// Library/extensions searching with Levenshtein distance
implementation("me.xdrop:fuzzywuzzy:1.4.0")
// color pallette for images -> colors
// color palette for images -> colors
implementation("androidx.palette:palette-ktx:1.0.0")
}

View File

@ -51,8 +51,8 @@ class CustomReportSender : ReportSender {
thread { // to not run it on main thread
runBlocking {
suspendSafeApiCall {
val post = app.post(url, data = data)
println("Report response: $post")
app.post(url, data = data)
//println("Report response: $post")
}
}
}

View File

@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.android.gms.cast.framework.*
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.navigationrail.NavigationRailView
import com.google.android.material.snackbar.Snackbar
@ -49,6 +50,9 @@ import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.databinding.ActivityMainBinding
import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding
import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding
import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.plugins.PluginManager
@ -74,6 +78,7 @@ import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.result.setImage
import com.lagradost.cloudstream3.ui.result.setText
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.ui.search.SearchFragment
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
@ -110,9 +115,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.ResponseParser
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.bottom_resultview_preview.*
import kotlinx.android.synthetic.main.fragment_result_swipe.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.File
@ -334,8 +336,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
// Use both navigation views to support both layouts.
// It might be better to use the QuickSearch.
nav_view?.selectedItemId = R.id.navigation_search
nav_rail_view?.selectedItemId = R.id.navigation_search
activity?.findViewById<BottomNavigationView>(R.id.nav_view)?.selectedItemId =
R.id.navigation_search
activity?.findViewById<NavigationRailView>(R.id.nav_rail_view)?.selectedItemId =
R.id.navigation_search
} else if (safeURI(str)?.scheme == appStringPlayer) {
val uri = Uri.parse(str)
val name = uri.getQueryParameter("name")
@ -412,7 +416,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
this.hideKeyboard()
// Fucks up anime info layout since that has its own layout
cast_mini_controller_holder?.isVisible =
binding?.castMiniControllerHolder?.isVisible =
!listOf(
R.id.navigation_results_phone,
R.id.navigation_results_tv,
@ -448,7 +452,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
R.id.navigation_player,
).contains(destination.id)
nav_host_fragment?.apply {
binding?.navHostFragment?.apply {
val params = layoutParams as ConstraintLayout.LayoutParams
params.setMargins(
@ -464,21 +468,24 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
Configuration.ORIENTATION_LANDSCAPE -> {
true
}
Configuration.ORIENTATION_PORTRAIT -> {
false
isTvSettings()
}
else -> {
false
}
}
binding?.apply {
navView.isVisible = isNavVisible && !landscape
navRailView.isVisible = isNavVisible && landscape
nav_view?.isVisible = isNavVisible && !landscape
nav_rail_view?.isVisible = isNavVisible && landscape
// Hide library on TV since it is not supported yet :(
val isTrueTv = isTrueTvSettings()
nav_view?.menu?.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
nav_rail_view?.menu?.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
// Hide library on TV since it is not supported yet :(
val isTrueTv = isTrueTvSettings()
navView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
navRailView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
}
}
//private var mCastSession: CastSession? = null
@ -691,28 +698,37 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
private fun hidePreviewPopupDialog() {
viewModel.clear()
bottomPreviewPopup.dismissSafe(this)
bottomPreviewPopup = null
bottomPreviewBinding = null
}
var bottomPreviewPopup: BottomSheetDialog? = null
private fun showPreviewPopupDialog(): BottomSheetDialog {
val ret = (bottomPreviewPopup ?: run {
private var bottomPreviewPopup: BottomSheetDialog? = null
private var bottomPreviewBinding: BottomResultviewPreviewBinding? = null
private fun showPreviewPopupDialog(): BottomResultviewPreviewBinding {
val ret = (bottomPreviewBinding ?: run {
val builder =
BottomSheetDialog(this)
builder.setContentView(R.layout.bottom_resultview_preview)
val binding: BottomResultviewPreviewBinding =
BottomResultviewPreviewBinding.inflate(builder.layoutInflater, null, false)
bottomPreviewBinding = binding
builder.setContentView(binding.root)
builder.setOnDismissListener {
bottomPreviewPopup = null
bottomPreviewBinding = null
viewModel.clear()
}
builder.setCanceledOnTouchOutside(true)
builder.show()
builder
bottomPreviewPopup = builder
binding
})
bottomPreviewPopup = ret
return ret
}
var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
app.initClient(this)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
@ -744,10 +760,20 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
updateTv()
if (isTvSettings()) {
setContentView(R.layout.activity_main_tv)
} else {
setContentView(R.layout.activity_main)
// just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH
binding = try {
if (isTvSettings()) {
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
setContentView(newLocalBinding.root)
ActivityMainBinding.bind(newLocalBinding.root) // this may crash
} else {
val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)
setContentView(newLocalBinding.root)
newLocalBinding
}
} catch (t: Throwable) {
showToast(this, txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG)
null
}
changeStatusBarState(isEmulatorSettings())
@ -832,41 +858,44 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
observeNullable(viewModel.page) { resource ->
if (resource == null) {
bottomPreviewPopup.dismissSafe(this)
hidePreviewPopupDialog()
return@observeNullable
}
when (resource) {
is Resource.Failure -> {
showToast(this, R.string.error)
viewModel.clear()
hidePreviewPopupDialog()
}
is Resource.Loading -> {
showPreviewPopupDialog().apply {
resultview_preview_loading?.isVisible = true
resultview_preview_result?.isVisible = false
resultview_preview_loading_shimmer?.startShimmer()
resultviewPreviewLoading.isVisible = true
resultviewPreviewResult.isVisible = false
resultviewPreviewLoadingShimmer.startShimmer()
}
}
is Resource.Success -> {
val d = resource.value
showPreviewPopupDialog().apply {
resultview_preview_loading?.isVisible = false
resultview_preview_result?.isVisible = true
resultview_preview_loading_shimmer?.stopShimmer()
resultviewPreviewLoading.isVisible = false
resultviewPreviewResult.isVisible = true
resultviewPreviewLoadingShimmer.stopShimmer()
resultview_preview_title?.text = d.title
resultviewPreviewTitle.text = d.title
resultview_preview_meta_type.setText(d.typeText)
resultview_preview_meta_year.setText(d.yearText)
resultview_preview_meta_duration.setText(d.durationText)
resultview_preview_meta_rating.setText(d.ratingText)
resultviewPreviewMetaType.setText(d.typeText)
resultviewPreviewMetaYear.setText(d.yearText)
resultviewPreviewMetaDuration.setText(d.durationText)
resultviewPreviewMetaRating.setText(d.ratingText)
resultview_preview_description?.setText(d.plotText)
resultview_preview_poster?.setImage(
resultviewPreviewDescription.setText(d.plotText)
resultviewPreviewPoster.setImage(
d.posterImage ?: d.posterBackgroundImage
)
resultview_preview_poster?.setOnClickListener {
resultviewPreviewPoster.setOnClickListener {
//viewModel.updateWatchStatus(WatchType.PLANTOWATCH)
val value = viewModel.watchStatus.value ?: WatchType.NONE
@ -882,7 +911,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
if (!isTvSettings()) // dont want this clickable on tv layout
resultview_preview_description?.setOnClickListener { view ->
resultviewPreviewDescription.setOnClickListener { view ->
view.context?.let { ctx ->
val builder: AlertDialog.Builder =
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
@ -892,7 +921,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
}
resultview_preview_more_info?.setOnClickListener {
resultviewPreviewMoreInfo.setOnClickListener {
viewModel.clear()
hidePreviewPopupDialog()
lastPopup?.let {
loadSearchResult(it)
@ -964,22 +994,22 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
.setPopExitAnim(R.anim.nav_pop_exit)
.setPopUpTo(navController.graph.startDestination, false)
.build()*/
nav_view?.setupWithNavController(navController)
val nav_rail = findViewById<NavigationRailView?>(R.id.nav_rail_view)
nav_rail?.setupWithNavController(navController)
binding?.navView?.setupWithNavController(navController)
val navRail = findViewById<NavigationRailView?>(R.id.nav_rail_view)
navRail?.setupWithNavController(navController)
if (isTvSettings()) {
nav_rail?.background?.alpha = 200
navRail?.background?.alpha = 200
} else {
nav_rail?.background?.alpha = 255
navRail?.background?.alpha = 255
}
nav_rail?.setOnItemSelectedListener { item ->
navRail?.setOnItemSelectedListener { item ->
onNavDestinationSelected(
item,
navController
)
}
nav_view?.setOnItemSelectedListener { item ->
binding?.navView?.setOnItemSelectedListener { item ->
onNavDestinationSelected(
item,
navController
@ -1010,16 +1040,16 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}*/
val rippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f))
nav_view?.itemRippleColor = rippleColor
nav_rail?.itemRippleColor = rippleColor
nav_rail?.itemActiveIndicatorColor = rippleColor
nav_view?.itemActiveIndicatorColor = rippleColor
binding?.navView?.itemRippleColor = rippleColor
navRail?.itemRippleColor = rippleColor
navRail?.itemActiveIndicatorColor = rippleColor
binding?.navView?.itemActiveIndicatorColor = rippleColor
if (!checkWrite()) {
requestRW()
if (checkWrite()) return
}
CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
//CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
// THIS IS CURRENTLY REMOVED BECAUSE HIGHER VERS OF ANDROID NEEDS A NOTIFICATION
//if (!VideoDownloadManager.isMyServiceRunning(this, VideoDownloadKeepAliveService::class.java)) {

View File

@ -31,6 +31,7 @@ import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.MainActivity.Companion.bookmarksUpdatedEvent
import com.lagradost.cloudstream3.MainActivity.Companion.mainPluginsLoadedEvent
@ -45,6 +46,7 @@ import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.ui.search.*
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
@ -431,22 +433,20 @@ class HomeFragment : Fragment() {
): View? {
//homeViewModel =
// ViewModelProvider(this).get(HomeViewModel::class.java)
bottomSheetDialog?.ownShow()
val layout =
if (isTvSettings()) R.layout.fragment_home_tv else R.layout.fragment_home
/* 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
binding = try {
FragmentHomeBinding.bind(root)
} catch (t : Throwable) {
showToast(activity, txt(R.string.unable_to_inflate, t.message ?: ""), Toast.LENGTH_LONG)
logError(t)
null
}
//return inflater.inflate(layout, container, false)
return root
}
override fun onDestroyView() {

View File

@ -2,13 +2,13 @@ package com.lagradost.cloudstream3.ui.library
import android.view.View
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.library_viewpager_page.view.*
import com.lagradost.cloudstream3.R
import kotlin.math.roundToInt
class LibraryScrollTransformer : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
val padding = (-position * page.width).roundToInt()
page.page_recyclerview.setPadding(
page.findViewById<View>(R.id.page_recyclerview).setPadding(
padding, 0,
-padding, 0
)

View File

@ -2,24 +2,18 @@ package com.lagradost.cloudstream3.ui.player.source_priority
import android.app.Dialog
import android.content.Context
import android.view.View
import android.widget.EditText
import android.widget.TextView
import android.view.LayoutInflater
import androidx.annotation.StyleRes
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.work.impl.constraints.controllers.ConstraintController
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.PlayerSelectSourcePriorityBinding
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import kotlinx.android.synthetic.main.player_select_source_priority.*
class SourcePriorityDialog(
ctx: Context,
val ctx: Context,
@StyleRes themeRes: Int,
val links: List<ExtractorLink>,
private val profile: QualityDataHelper.QualityProfile,
@ -30,13 +24,14 @@ class SourcePriorityDialog(
private val updatedCallback: () -> Unit
) : Dialog(ctx, themeRes) {
override fun show() {
setContentView(R.layout.player_select_source_priority)
val sourcesRecyclerView: RecyclerView = sort_sources
val qualitiesRecyclerView: RecyclerView = sort_qualities
val profileText: EditText = profile_text_editable
val saveBtt: View = save_btt
val exitBtt: View = close_btt
val helpBtt: View = help_btt
val binding = PlayerSelectSourcePriorityBinding.inflate(LayoutInflater.from(ctx), null, false)
setContentView(binding.root)
val sourcesRecyclerView = binding.sortSources
val qualitiesRecyclerView = binding.sortQualities
val profileText = binding.profileTextEditable
val saveBtt = binding.saveBtt
val exitBtt = binding.closeBtt
val helpBtt = binding.helpBtt
profileText.setText(QualityDataHelper.getProfileName(profile.id).asString(context))
profileText.hint = txt(R.string.profile_number, profile.id).asString(context)

View File

@ -38,15 +38,15 @@ class SearchAdapter(
var hasNext: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val layout =
if (parent.context.IsBottomLayout()) SearchResultGridExpandedBinding.inflate(
LayoutInflater.from(parent.context),
inflater,
parent,
false
) else SearchResultGridBinding.inflate(
LayoutInflater.from(parent.context),
inflater,
parent,
false
) //R.layout.search_result_grid_expanded else R.layout.search_result_grid
@ -95,9 +95,15 @@ class SearchAdapter(
private val coverHeight: Int =
if (compactView) 80.toPx else (resView.itemWidth / 0.68).roundToInt()
private val cardView = when(binding) {
is SearchResultGridExpandedBinding -> binding.imageView
is SearchResultGridBinding -> binding.imageView
else -> null
}
fun bind(card: SearchResponse, position: Int) {
if (!compactView) {
binding.root.apply {
cardView?.apply {
layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
coverHeight

View File

@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.ui.settings.extensions
import android.text.format.Formatter.formatShortFileSize
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isGone
@ -13,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity
import com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.plugins.VotingApi.getVotes
import com.lagradost.cloudstream3.ui.result.setText
@ -26,10 +26,11 @@ import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.repository_item.view.*
import org.junit.Assert
import org.junit.Test
import java.text.DecimalFormat
import kotlin.math.floor
import kotlin.math.log10
data class PluginViewData(
@ -45,8 +46,10 @@ class PluginAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layout = if(isTrueTvSettings()) R.layout.repository_item_tv else R.layout.repository_item
val inflated = LayoutInflater.from(parent.context).inflate(layout, parent, false)
return PluginViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false)
RepositoryItemBinding.bind(inflated) // may crash
)
}
@ -82,8 +85,10 @@ class PluginAdapter(
// Clear glide image because setImageResource doesn't override
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
holder.itemView.entry_icon?.let { pluginIcon ->
GlideApp.with(pluginIcon).clear(pluginIcon)
if (holder is PluginViewHolder) {
holder.binding.entryIcon.let { pluginIcon ->
GlideApp.with(pluginIcon).clear(pluginIcon)
}
}
super.onViewRecycled(holder)
}
@ -112,7 +117,7 @@ class PluginAdapter(
fun prettyCount(number: Number): String? {
val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')
val numValue = number.toLong()
val value = Math.floor(Math.log10(numValue.toDouble())).toInt()
val value = floor(log10(numValue.toDouble())).toInt()
val base = value / 3
return if (value >= 3 && base < suffix.size) {
DecimalFormat("#0.00").format(
@ -127,8 +132,8 @@ class PluginAdapter(
}
}
inner class PluginViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
inner class PluginViewHolder(val binding: RepositoryItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(
data: PluginViewData,
@ -138,17 +143,17 @@ class PluginAdapter(
val name = metadata.name.removeSuffix("Provider")
val alpha = if (disabled) 0.6f else 1f
val isLocal = !data.plugin.second.url.startsWith("http")
itemView.main_text?.alpha = alpha
itemView.sub_text?.alpha = alpha
binding.mainText.alpha = alpha
binding.subText.alpha = alpha
val drawableInt = if (data.isDownloaded)
R.drawable.ic_baseline_delete_outline_24
else R.drawable.netflix_download
itemView.nsfw_marker?.isVisible = metadata.tvTypes?.contains("NSFW") ?: false
itemView.action_button?.setImageResource(drawableInt)
binding.nsfwMarker.isVisible = metadata.tvTypes?.contains("NSFW") ?: false
binding.actionButton.setImageResource(drawableInt)
itemView.action_button?.setOnClickListener {
binding.actionButton.setOnClickListener {
iconClickCallback.invoke(data.plugin)
}
itemView.setOnClickListener {
@ -169,10 +174,11 @@ class PluginAdapter(
if (data.isDownloaded) {
// On local plugins page the filepath is provided instead of url.
val plugin = PluginManager.urlPlugins[metadata.url] ?: PluginManager.plugins[metadata.url]
val plugin =
PluginManager.urlPlugins[metadata.url] ?: PluginManager.plugins[metadata.url]
if (plugin?.openSettings != null) {
itemView.action_settings?.isVisible = true
itemView.action_settings.setOnClickListener {
binding.actionSettings.isVisible = true
binding.actionSettings.setOnClickListener {
try {
plugin.openSettings!!.invoke(itemView.context)
} catch (e: Throwable) {
@ -185,13 +191,13 @@ class PluginAdapter(
}
}
} else {
itemView.action_settings?.isVisible = false
binding.actionSettings.isVisible = false
}
} else {
itemView.action_settings?.isVisible = false
binding.actionSettings.isVisible = false
}
if (itemView.entry_icon?.setImage(//itemView.entry_icon?.height ?:
if (!binding.entryIcon.setImage(//itemView.entry_icon?.height ?:
metadata.iconUrl?.replace(
"%size%",
"$iconSize"
@ -201,41 +207,47 @@ class PluginAdapter(
),
null,
errorImageDrawable = R.drawable.ic_baseline_extension_24
) != true
)
) {
itemView.entry_icon?.setImageResource(R.drawable.ic_baseline_extension_24)
binding.entryIcon.setImageResource(R.drawable.ic_baseline_extension_24)
}
itemView.ext_version?.isVisible = true
itemView.ext_version?.text = "v${metadata.version}"
binding.extVersion.isVisible = true
binding.extVersion.text = "v${metadata.version}"
if (metadata.language.isNullOrBlank()) {
itemView.lang_icon?.isVisible = false
binding.langIcon.isVisible = false
} else {
itemView.lang_icon?.isVisible = true
itemView.lang_icon.text = "${getFlagFromIso(metadata.language)} ${fromTwoLettersToLanguage(metadata.language)}"
binding.langIcon.isVisible = true
binding.langIcon.text =
"${getFlagFromIso(metadata.language)} ${fromTwoLettersToLanguage(metadata.language)}"
}
itemView.ext_votes?.isVisible = false
binding.extVotes.isVisible = false
if (!isLocal) {
ioSafe {
metadata.getVotes().main {
itemView.ext_votes?.setText(txt(R.string.extension_rating, prettyCount(it)))
itemView.ext_votes?.isVisible = true
binding.extVotes.setText(txt(R.string.extension_rating, prettyCount(it)))
binding.extVotes.isVisible = true
}
}
}
if (metadata.fileSize != null) {
itemView.ext_filesize?.isVisible = true
itemView.ext_filesize?.text = formatShortFileSize(itemView.context, metadata.fileSize)
binding.extFilesize.isVisible = true
binding.extFilesize.text = formatShortFileSize(itemView.context, metadata.fileSize)
} else {
itemView.ext_filesize?.isVisible = false
binding.extFilesize.isVisible = false
}
itemView.main_text.setText(if(disabled) txt(R.string.single_plugin_disabled, name) else txt(name))
itemView.sub_text?.isGone = metadata.description.isNullOrBlank()
itemView.sub_text?.text = metadata.description.html()
binding.mainText.setText(
if (disabled) txt(
R.string.single_plugin_disabled,
name
) else txt(name)
)
binding.subText.isGone = metadata.description.isNullOrBlank()
binding.subText.text = metadata.description.html()
}
}
}

View File

@ -181,6 +181,50 @@ object UIHelper {
}
}
/*inline fun <reified T : ViewBinding> bindViewBinding(
inflater: LayoutInflater?,
container: ViewGroup?,
layout: Int
): Pair<T?, UiText?> {
return try {
val localInflater = inflater ?: container?.context?.let { LayoutInflater.from(it) }
?: return null to txt(
R.string.unable_to_inflate,
"Requires inflater OR container"
)//throw IllegalArgumentException("Requires inflater OR container"))
//println("methods: ${T::class.java.methods.map { it.name }}")
val bind = T::class.java.methods.first { it.name == "bind" }
//val inflate = T::class.java.methods.first { it.name == "inflate" }
val root = localInflater.inflate(layout, container, false)
bind.invoke(null, root) as T to null
} catch (t: Throwable) {
logError(t)
val message = txt(R.string.unable_to_inflate, t.message ?: "Primary constructor")
// if the desired layout is not found then we inflate the casted layout
/*try {
val localInflater = inflater ?: container?.context?.let { LayoutInflater.from(it) }
?: return null to txt(
R.string.unable_to_inflate,
"Requires inflater OR container"
)//throw IllegalArgumentException("Requires inflater OR container"))
// we don't know what method to use as there are 2, but first *should* always be true
return try {
val inflate = T::class.java.methods.first { it.name == "inflate" }
inflate.invoke(null, localInflater, container, false) as T
} catch (_: Throwable) {
val inflate = T::class.java.methods.last { it.name == "inflate" }
inflate.invoke(null, localInflater, container, false) as T
} to message
} catch (t: Throwable) {
logError(t)
}*/
null to message
}
}*/
fun ImageView?.setImage(
url: String?,
headers: Map<String, String>? = null,
@ -190,7 +234,12 @@ object UIHelper {
colorCallback: ((Palette) -> Unit)? = null
): Boolean {
if (url.isNullOrBlank()) return false
this.setImage(UiImage.Image(url, headers, errorImageDrawable), errorImageDrawable, fadeIn, colorCallback)
this.setImage(
UiImage.Image(url, headers, errorImageDrawable),
errorImageDrawable,
fadeIn,
colorCallback
)
return true
}

View File

@ -41,6 +41,22 @@
</com.google.android.material.navigationrail.NavigationRailView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_height="70dp"
android:layout_width="0dp"
app:labelVisibilityMode="unlabeled"
android:visibility="gone"
android:background="?attr/primaryGrayBackground"
app:itemIconTint="@color/item_select_color"
app:itemTextColor="@color/item_select_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
<LinearLayout
android:id="@+id/cast_mini_controller_holder"
android:layout_width="0dp"

View File

@ -677,4 +677,5 @@
</string>
<string name="qualities">Qualities</string>
<string name="profile_background_des">Profile background</string>
<string name="unable_to_inflate">UI was unable to be created correctly, this is a MAJOR BUG and should be reported immediately %s</string>
</resources>