mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Initial implementation for Library on TV
This commit is contained in:
parent
f14557fe6a
commit
a4a96c514b
5 changed files with 282 additions and 23 deletions
|
@ -542,9 +542,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
navRailView.isVisible = isNavVisible && landscape
|
||||
|
||||
// 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
|
||||
//val isTrueTv = isTrueTvSettings()
|
||||
//navView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
||||
//navRailView.menu.findItem(R.id.navigation_library)?.isVisible = !isTrueTv
|
||||
|
||||
// Hide downloads on TV
|
||||
//navView.menu.findItem(R.id.navigation_downloads)?.isVisible = !isTrueTv
|
||||
|
@ -904,6 +904,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
val visible =
|
||||
newFocus != null && newFocus.measuredHeight > 0 && newFocus.measuredWidth > 0 && newFocus.isShown && newFocus.tag != "tv_no_focus_tag"
|
||||
focusOutline.isVisible = visible
|
||||
//Todo Clean this
|
||||
Log.d("King","${newFocus?.tag}:${newFocus.toString()}")
|
||||
|
||||
if (newFocus != null) {
|
||||
lastFocus = WeakReference(newFocus)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.library
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
|
@ -10,22 +11,27 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.lagradost.cloudstream3.APIHolder
|
||||
import com.lagradost.cloudstream3.APIHolder.allProviders
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
||||
|
@ -33,6 +39,7 @@ import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
|||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
|
||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.reduceDragSensitivity
|
||||
|
@ -80,9 +87,21 @@ class LibraryFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
val localBinding = FragmentLibraryBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root
|
||||
val layout =
|
||||
if (SettingsFragment.isTvSettings()) R.layout.fragment_library_tv else R.layout.fragment_library
|
||||
val root = inflater.inflate(layout, container, false)
|
||||
binding = try {
|
||||
FragmentLibraryBinding.bind(root)
|
||||
} catch (t: Throwable) {
|
||||
CommonActivity.showToast(
|
||||
txt(R.string.unable_to_inflate, t.message ?: ""),
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
logError(t)
|
||||
null
|
||||
}
|
||||
|
||||
return root
|
||||
|
||||
//return inflater.inflate(R.layout.fragment_library, container, false)
|
||||
}
|
||||
|
@ -99,25 +118,15 @@ class LibraryFragment : Fragment() {
|
|||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType", "CutPasteId")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
fixPaddingStatusbar(binding?.searchStatusBarPadding)
|
||||
|
||||
binding?.sortFab?.setOnClickListener {
|
||||
val methods = libraryViewModel.sortingMethods.map {
|
||||
txt(it.stringRes).asString(view.context)
|
||||
}
|
||||
binding?.sortFab?.setOnClickListener(sortChangeClickListener)
|
||||
binding?.librarySort?.setOnClickListener(sortChangeClickListener)
|
||||
|
||||
activity?.showBottomDialog(methods,
|
||||
libraryViewModel.sortingMethods.indexOf(libraryViewModel.currentSortingMethod),
|
||||
txt(R.string.sort_by).asString(view.context),
|
||||
false,
|
||||
{},
|
||||
{
|
||||
val method = libraryViewModel.sortingMethods[it]
|
||||
libraryViewModel.sort(method)
|
||||
})
|
||||
}
|
||||
binding?.libraryRoot?.findViewById<TextView>(R.id.search_src_text)?.tag = "tv_no_focus_tag"
|
||||
|
||||
binding?.mainSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
|
@ -266,7 +275,10 @@ class LibraryFragment : Fragment() {
|
|||
// selects the whole list opener
|
||||
val savedListSelection =
|
||||
getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncName.name)
|
||||
val savedSelection = getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncId).takeIf {
|
||||
val savedSelection = getKey<LibraryOpener>(
|
||||
"$currentAccount/$LIBRARY_FOLDER",
|
||||
syncId
|
||||
).takeIf {
|
||||
it?.openType != LibraryOpenerType.Default
|
||||
} ?: savedListSelection
|
||||
|
||||
|
@ -354,6 +366,9 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
|
||||
(viewpager.adapter as? ViewpagerAdapter)?.pages = pages
|
||||
//fix focus on the viewpager itself
|
||||
(viewpager.getChildAt(0) as RecyclerView).tag = "tv_no_focus_tag"
|
||||
|
||||
// Using notifyItemRangeChanged keeps the animations when sorting
|
||||
viewpager.adapter?.notifyItemRangeChanged(
|
||||
0,
|
||||
|
@ -396,6 +411,11 @@ class LibraryFragment : Fragment() {
|
|||
viewpager,
|
||||
) { tab, position ->
|
||||
tab.text = pages.getOrNull(position)?.title?.asStringNull(context)
|
||||
tab.view.tag = "tv_no_focus_tag"
|
||||
tab.view.nextFocusUpId = R.id.search_result_root
|
||||
/*tab.view.setOnFocusChangeListener { view, b ->
|
||||
Log.d("King", libraryTabLayout.focusedChild)
|
||||
}*/
|
||||
tab.view.setOnClickListener {
|
||||
val currentItem =
|
||||
binding?.viewpager?.currentItem ?: return@setOnClickListener
|
||||
|
@ -429,6 +449,22 @@ class LibraryFragment : Fragment() {
|
|||
(binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind()
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
|
||||
private val sortChangeClickListener = View.OnClickListener { view ->
|
||||
val methods = libraryViewModel.sortingMethods.map {
|
||||
txt(it.stringRes).asString(view.context)
|
||||
}
|
||||
|
||||
activity?.showBottomDialog(methods,
|
||||
libraryViewModel.sortingMethods.indexOf(libraryViewModel.currentSortingMethod),
|
||||
txt(R.string.sort_by).asString(view.context),
|
||||
false,
|
||||
{},
|
||||
{
|
||||
val method = libraryViewModel.sortingMethods[it]
|
||||
libraryViewModel.sort(method)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class MenuSearchView(context: Context) : SearchView(context) {
|
||||
|
|
|
@ -41,6 +41,20 @@
|
|||
android:src="@drawable/ic_baseline_extension_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/library_sort"
|
||||
android:layout_width="45dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:padding="5dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:src="@drawable/ic_baseline_sort_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
|
@ -160,8 +174,7 @@
|
|||
android:layout_height="40dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?attr/primaryGrayBackground"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:focusable="false"
|
||||
android:focusable="true"
|
||||
android:paddingHorizontal="5dp"
|
||||
app:layout_scrollFlags="noScroll"
|
||||
app:tabGravity="center"
|
||||
|
|
206
app/src/main/res/layout/fragment_library_tv.xml
Normal file
206
app/src/main/res/layout/fragment_library_tv.xml
Normal file
|
@ -0,0 +1,206 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/library_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_list_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="30dp"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/search_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/primaryGrayBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_status_bar_padding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/provider_selector"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:padding="2dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
android:nextFocusRight="@id/library_sort"
|
||||
android:nextFocusDown="@id/search_result_root"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:src="@drawable/ic_baseline_extension_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/library_sort"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/provider_selector"
|
||||
android:nextFocusRight="@id/list_selector"
|
||||
android:nextFocusDown="@id/search_result_root"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:src="@drawable/ic_baseline_sort_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/list_selector"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:padding="1dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/change_providers_img_des"
|
||||
android:nextFocusLeft="@id/library_sort"
|
||||
android:nextFocusRight="@id/main_search"
|
||||
android:nextFocusDown="@id/search_result_root"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:src="@drawable/ic_baseline_filter_list_24"
|
||||
app:tint="?attr/textColor" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:visibility="visible"
|
||||
android:nextFocusDown="@id/search_result_root"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/main_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
|
||||
android:iconifiedByDefault="false"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="text"
|
||||
android:focusable="true"
|
||||
android:tag="tv_no_focus_tag"
|
||||
android:nextFocusLeft="@id/list_selector"
|
||||
android:nextFocusDown="@id/search_result_root"
|
||||
android:paddingStart="-10dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@color/transparent"
|
||||
app:queryHint="@string/search_hint"
|
||||
app:searchIcon="@drawable/search_icon"
|
||||
tools:ignore="RtlSymmetry">
|
||||
|
||||
</androidx.appcompat.widget.SearchView>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="40dp"
|
||||
android:focusable="false"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
tools:listitem="@layout/library_viewpager_page" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/library_loading_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
android:id="@+id/library_loading_shimmer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="2dp"
|
||||
app:shimmer_auto_start="true"
|
||||
app:shimmer_base_alpha="0.2"
|
||||
android:focusable="false"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
app:shimmer_duration="@integer/loading_time"
|
||||
app:shimmer_highlight_alpha="0.3">
|
||||
|
||||
<GridView
|
||||
android:id="@+id/gridview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="center"
|
||||
android:horizontalSpacing="10dp"
|
||||
android:numColumns="3"
|
||||
android:paddingBottom="120dp"
|
||||
android:focusable="false"
|
||||
android:tag="@string/tv_no_focus_tag"
|
||||
android:verticalSpacing="10dp"
|
||||
tools:listitem="@layout/loading_poster_dynamic" />
|
||||
</com.facebook.shimmer.ShimmerFrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="40dp">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/sort_fab"
|
||||
style="@style/ExtendedFloatingActionButton"
|
||||
android:text="@string/sort"
|
||||
android:textColor="?attr/textColor"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_sort_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/library_tab_layout"
|
||||
style="@style/Theme.Widget.Tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:nextFocusUp="@id/search_result_root"
|
||||
android:background="?attr/primaryGrayBackground"
|
||||
android:nextFocusLeft="@id/nav_rail_view"
|
||||
android:paddingHorizontal="5dp"
|
||||
app:layout_scrollFlags="noScroll"
|
||||
app:tabGravity="center"
|
||||
app:tabIndicator="@drawable/indicator_background"
|
||||
app:tabIndicatorColor="?attr/white"
|
||||
app:tabIndicatorGravity="center"
|
||||
app:tabIndicatorHeight="30dp"
|
||||
app:tabMode="scrollable"
|
||||
app:tabSelectedTextColor="?attr/primaryBlackBackground"
|
||||
app:tabTextAppearance="@style/TabNoCaps"
|
||||
app:tabTextColor="?attr/textColor" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -5,5 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:focusable="false"
|
||||
android:tag="tv_no_focus_tag"
|
||||
tools:listitem="@layout/home_result_grid_expanded" />
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue