mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
more views + MainActivity viewbindings
This commit is contained in:
parent
166a21f74e
commit
647e91bc4b
11 changed files with 237 additions and 128 deletions
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
nav_view?.isVisible = isNavVisible && !landscape
|
||||
nav_rail_view?.isVisible = isNavVisible && landscape
|
||||
binding?.apply {
|
||||
navView.isVisible = isNavVisible && !landscape
|
||||
navRailView.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
|
||||
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()
|
||||
|
||||
// just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH
|
||||
binding = try {
|
||||
if (isTvSettings()) {
|
||||
setContentView(R.layout.activity_main_tv)
|
||||
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
||||
setContentView(newLocalBinding.root)
|
||||
ActivityMainBinding.bind(newLocalBinding.root) // this may crash
|
||||
} else {
|
||||
setContentView(R.layout.activity_main)
|
||||
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)) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,9 +85,11 @@ class PluginAdapter(
|
|||
|
||||
// Clear glide image because setImageResource doesn't override
|
||||
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
|
||||
holder.itemView.entry_icon?.let { 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue