mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
feat: Support multiple filter selection (#5478)
Co-authored-by: Bnyro <82752168+Bnyro@users.noreply.github.com>
This commit is contained in:
parent
0e960e1a6c
commit
444eb693d4
@ -34,4 +34,5 @@ object IntentData {
|
|||||||
const val bitmapUrl = "bitmapUrl"
|
const val bitmapUrl = "bitmapUrl"
|
||||||
const val isCurrentlyPlaying = "isCurrentlyPlaying"
|
const val isCurrentlyPlaying = "isCurrentlyPlaying"
|
||||||
const val isSubscribed = "isSubscribed"
|
const val isSubscribed = "isSubscribed"
|
||||||
|
const val sortOptions = "sortOptions"
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ object PreferenceKeys {
|
|||||||
const val LAST_STREAM_VIDEO_ID = "last_stream_video_id"
|
const val LAST_STREAM_VIDEO_ID = "last_stream_video_id"
|
||||||
const val LAST_WATCHED_FEED_TIME = "last_watched_feed_time"
|
const val LAST_WATCHED_FEED_TIME = "last_watched_feed_time"
|
||||||
const val HIDE_WATCHED_FROM_FEED = "hide_watched_from_feed"
|
const val HIDE_WATCHED_FROM_FEED = "hide_watched_from_feed"
|
||||||
const val SELECTED_FEED_FILTER = "filer_feed"
|
const val SELECTED_FEED_FILTERS = "filter_feed"
|
||||||
const val FEED_SORT_ORDER = "sort_oder_feed"
|
const val FEED_SORT_ORDER = "sort_oder_feed"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.github.libretube.enums
|
||||||
|
|
||||||
|
import com.github.libretube.constants.PreferenceKeys.SELECTED_FEED_FILTERS
|
||||||
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
|
|
||||||
|
enum class ContentFilter {
|
||||||
|
VIDEOS,
|
||||||
|
SHORTS,
|
||||||
|
LIVESTREAMS;
|
||||||
|
|
||||||
|
fun isEnabled() = enabledFiltersSet.contains(ordinal.toString())
|
||||||
|
|
||||||
|
fun setState(enabled: Boolean) {
|
||||||
|
val newFilters = enabledFiltersSet
|
||||||
|
.apply {if (enabled) add(ordinal.toString()) else remove(ordinal.toString()) }
|
||||||
|
.joinToString(",")
|
||||||
|
|
||||||
|
PreferenceHelper.putString(SELECTED_FEED_FILTERS, newFilters)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val enabledFiltersSet get() = PreferenceHelper
|
||||||
|
.getString(
|
||||||
|
key = SELECTED_FEED_FILTERS,
|
||||||
|
defValue = entries.joinToString(",") { it.ordinal.toString() }
|
||||||
|
)
|
||||||
|
.split(',')
|
||||||
|
.toMutableSet()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.github.libretube.obj
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class SelectableOption(
|
||||||
|
val isSelected: Boolean,
|
||||||
|
val name: String
|
||||||
|
): Parcelable
|
@ -23,6 +23,7 @@ import com.github.libretube.constants.PreferenceKeys
|
|||||||
import com.github.libretube.databinding.FragmentHomeBinding
|
import com.github.libretube.databinding.FragmentHomeBinding
|
||||||
import com.github.libretube.db.DatabaseHelper
|
import com.github.libretube.db.DatabaseHelper
|
||||||
import com.github.libretube.db.DatabaseHolder
|
import com.github.libretube.db.DatabaseHolder
|
||||||
|
import com.github.libretube.enums.ContentFilter
|
||||||
import com.github.libretube.helpers.LocaleHelper
|
import com.github.libretube.helpers.LocaleHelper
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
@ -145,12 +146,13 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
|
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val allowShorts = ContentFilter.SHORTS.isEnabled()
|
||||||
|
val allowVideos = ContentFilter.VIDEOS.isEnabled()
|
||||||
|
val allowAll = (!allowShorts && !allowVideos)
|
||||||
|
|
||||||
var filteredFeed = feed.filter {
|
var filteredFeed = feed.filter {
|
||||||
when (PreferenceHelper.getInt(PreferenceKeys.SELECTED_FEED_FILTER, 0)) {
|
(allowShorts && it.isShort) || (allowVideos && !it.isShort) || allowAll
|
||||||
1 -> !it.isShort
|
|
||||||
2 -> it.isShort
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
||||||
filteredFeed = runBlocking { DatabaseHelper.filterUnwatched(filteredFeed) }
|
filteredFeed = runBlocking { DatabaseHelper.filterUnwatched(filteredFeed) }
|
||||||
|
@ -6,6 +6,8 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@ -16,15 +18,18 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.obj.StreamItem
|
import com.github.libretube.api.obj.StreamItem
|
||||||
|
import com.github.libretube.constants.IntentData
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
||||||
import com.github.libretube.db.DatabaseHelper
|
import com.github.libretube.db.DatabaseHelper
|
||||||
import com.github.libretube.db.DatabaseHolder
|
import com.github.libretube.db.DatabaseHolder
|
||||||
|
import com.github.libretube.enums.ContentFilter
|
||||||
import com.github.libretube.extensions.dpToPx
|
import com.github.libretube.extensions.dpToPx
|
||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.helpers.NavigationHelper
|
import com.github.libretube.helpers.NavigationHelper
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
|
import com.github.libretube.obj.SelectableOption
|
||||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||||
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
@ -32,8 +37,10 @@ import com.github.libretube.ui.base.DynamicLayoutManagerFragment
|
|||||||
import com.github.libretube.ui.models.EditChannelGroupsModel
|
import com.github.libretube.ui.models.EditChannelGroupsModel
|
||||||
import com.github.libretube.ui.models.PlayerViewModel
|
import com.github.libretube.ui.models.PlayerViewModel
|
||||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
|
||||||
import com.github.libretube.ui.sheets.ChannelGroupsSheet
|
import com.github.libretube.ui.sheets.ChannelGroupsSheet
|
||||||
|
import com.github.libretube.ui.sheets.FilterSortBottomSheet
|
||||||
|
import com.github.libretube.ui.sheets.FilterSortBottomSheet.Companion.FILTER_SORT_REQUEST_KEY
|
||||||
|
import com.github.libretube.ui.sheets.FilterSortBottomSheet.Companion.SELECTED_SORT_OPTION_KEY
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -57,11 +64,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
|
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
private var selectedFilter = PreferenceHelper.getInt(PreferenceKeys.SELECTED_FEED_FILTER, 0)
|
|
||||||
set(value) {
|
|
||||||
PreferenceHelper.putInt(PreferenceKeys.SELECTED_FEED_FILTER, value)
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -84,9 +86,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
// update the text according to the current order and filter
|
setupSortAndFilter()
|
||||||
binding.sortTV.text = resources.getStringArray(R.array.sortOptions)[selectedSortOrder]
|
|
||||||
binding.filterTV.text = resources.getStringArray(R.array.filterOptions)[selectedFilter]
|
|
||||||
|
|
||||||
binding.subRefresh.isEnabled = true
|
binding.subRefresh.isEnabled = true
|
||||||
binding.subProgress.isVisible = true
|
binding.subProgress.isVisible = true
|
||||||
@ -109,30 +109,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
viewModel.fetchFeed(requireContext())
|
viewModel.fetchFeed(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.sortTV.setOnClickListener {
|
|
||||||
val sortOptions = resources.getStringArray(R.array.sortOptions)
|
|
||||||
|
|
||||||
BaseBottomSheet().apply {
|
|
||||||
setSimpleItems(sortOptions.toList()) { index ->
|
|
||||||
binding.sortTV.text = sortOptions[index]
|
|
||||||
selectedSortOrder = index
|
|
||||||
showFeed()
|
|
||||||
}
|
|
||||||
}.show(childFragmentManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.filterTV.setOnClickListener {
|
|
||||||
val filterOptions = resources.getStringArray(R.array.filterOptions)
|
|
||||||
|
|
||||||
BaseBottomSheet().apply {
|
|
||||||
setSimpleItems(filterOptions.toList()) { index ->
|
|
||||||
binding.filterTV.text = filterOptions[index]
|
|
||||||
selectedFilter = index
|
|
||||||
showFeed()
|
|
||||||
}
|
|
||||||
}.show(childFragmentManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.toggleSubs.isVisible = true
|
binding.toggleSubs.isVisible = true
|
||||||
|
|
||||||
binding.toggleSubs.setOnClickListener {
|
binding.toggleSubs.setOnClickListener {
|
||||||
@ -196,6 +172,33 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupSortAndFilter() {
|
||||||
|
binding.filterSort.setOnClickListener {
|
||||||
|
val activityCompat = context as AppCompatActivity
|
||||||
|
val fragManager = activityCompat
|
||||||
|
.supportFragmentManager
|
||||||
|
.apply {
|
||||||
|
setFragmentResultListener(FILTER_SORT_REQUEST_KEY, activityCompat) { _, resultBundle ->
|
||||||
|
selectedSortOrder = resultBundle.getInt(SELECTED_SORT_OPTION_KEY)
|
||||||
|
showFeed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterSortBottomSheet()
|
||||||
|
.apply { arguments = bundleOf(IntentData.sortOptions to fetchSortOptions()) }
|
||||||
|
.show(fragManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchSortOptions(): Array<SelectableOption> {
|
||||||
|
return resources
|
||||||
|
.getStringArray(R.array.sortOptions)
|
||||||
|
.mapIndexed { index, option ->
|
||||||
|
SelectableOption(isSelected = index == selectedSortOrder, name = option)
|
||||||
|
}
|
||||||
|
.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
@ -258,15 +261,17 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun List<StreamItem>.filterByStatusAndWatchPosition(): List<StreamItem> {
|
private fun List<StreamItem>.filterByStatusAndWatchPosition(): List<StreamItem> {
|
||||||
|
|
||||||
val streamItems = this.filter {
|
val streamItems = this.filter {
|
||||||
val isLive = (it.duration ?: -1L) < 0L
|
val isVideo = !it.isShort && !it.isLive
|
||||||
when (selectedFilter) {
|
|
||||||
0 -> true
|
return@filter when {
|
||||||
1 -> !it.isShort && !isLive
|
!ContentFilter.SHORTS.isEnabled() && it.isShort -> false
|
||||||
2 -> it.isShort
|
!ContentFilter.VIDEOS.isEnabled() && isVideo -> false
|
||||||
3 -> isLive
|
!ContentFilter.LIVESTREAMS.isEnabled() && it.isLive -> false
|
||||||
else -> throw IllegalArgumentException()
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PreferenceHelper.getBoolean(
|
if (!PreferenceHelper.getBoolean(
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
package com.github.libretube.ui.sheets
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import com.github.libretube.constants.IntentData
|
||||||
|
import com.github.libretube.databinding.FilterSortSheetBinding
|
||||||
|
import com.github.libretube.enums.ContentFilter
|
||||||
|
import com.github.libretube.obj.SelectableOption
|
||||||
|
|
||||||
|
class FilterSortBottomSheet: ExpandedBottomSheet() {
|
||||||
|
|
||||||
|
private var _binding: FilterSortSheetBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private lateinit var sortOptions: Array<SelectableOption>
|
||||||
|
|
||||||
|
private var selectedIndex: Int = 0
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
sortOptions = requireArguments().getParcelableArray(IntentData.sortOptions) as Array<SelectableOption>
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
_binding = FilterSortSheetBinding.inflate(layoutInflater)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
addSortOptions()
|
||||||
|
observeSortChanges()
|
||||||
|
setInitialFiltersState()
|
||||||
|
observeFiltersChanges()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addSortOptions() {
|
||||||
|
for (i in sortOptions.indices) {
|
||||||
|
val option = sortOptions.elementAt(i)
|
||||||
|
val rb = createRadioButton(i, option.name)
|
||||||
|
|
||||||
|
binding.sortRadioGroup.addView(rb)
|
||||||
|
|
||||||
|
if (option.isSelected) {
|
||||||
|
selectedIndex = i
|
||||||
|
binding.sortRadioGroup.check(rb.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRadioButton(index: Int, name: String): RadioButton {
|
||||||
|
return RadioButton(context).apply {
|
||||||
|
tag = index
|
||||||
|
text = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSortChanges() {
|
||||||
|
binding.sortRadioGroup.setOnCheckedChangeListener { group, checkedId ->
|
||||||
|
val index = group.findViewById<RadioButton>(checkedId).tag as Int
|
||||||
|
selectedIndex = index
|
||||||
|
notifyChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInitialFiltersState() {
|
||||||
|
binding.filterVideos.isChecked = ContentFilter.VIDEOS.isEnabled()
|
||||||
|
binding.filterShorts.isChecked = ContentFilter.SHORTS.isEnabled()
|
||||||
|
binding.filterLivestreams.isChecked = ContentFilter.LIVESTREAMS.isEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeFiltersChanges() {
|
||||||
|
binding.filters.setOnCheckedStateChangeListener { _, _ ->
|
||||||
|
ContentFilter.VIDEOS.setState(binding.filterVideos.isChecked)
|
||||||
|
ContentFilter.SHORTS.setState(binding.filterShorts.isChecked)
|
||||||
|
ContentFilter.LIVESTREAMS.setState(binding.filterLivestreams.isChecked)
|
||||||
|
notifyChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun notifyChange() {
|
||||||
|
setFragmentResult(
|
||||||
|
requestKey = FILTER_SORT_REQUEST_KEY,
|
||||||
|
result = bundleOf(SELECTED_SORT_OPTION_KEY to selectedIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val FILTER_SORT_REQUEST_KEY = "filter_sort_request_key"
|
||||||
|
const val SELECTED_SORT_OPTION_KEY = "selected_sort_option_key"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
app/src/main/res/drawable/ic_filter_sort.xml
Normal file
12
app/src/main/res/drawable/ic_filter_sort.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
|
||||||
|
|
||||||
|
</vector>
|
98
app/src/main/res/layout/filter_sort_sheet.xml
Normal file
98
app/src/main/res/layout/filter_sort_sheet.xml
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/standard_bottom_sheet"
|
||||||
|
style="@style/Widget.Material3.BottomSheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Drag handle for accessibility -->
|
||||||
|
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:text="@string/tooltip_filter" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/filters"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
app:selectionRequired="true"
|
||||||
|
app:singleLine="false"
|
||||||
|
app:singleSelection="false"
|
||||||
|
app:chipMinTouchTargetSize="0dp">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/filter_videos"
|
||||||
|
style="@style/ElevatedFilterChip"
|
||||||
|
android:layout_marginHorizontal="0dp"
|
||||||
|
app:chipSpacingVertical="10dp"
|
||||||
|
app:chipEndPadding="6dp"
|
||||||
|
app:chipStartPadding="6dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/videos" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/filter_shorts"
|
||||||
|
style="@style/ElevatedFilterChip"
|
||||||
|
android:layout_marginHorizontal="0dp"
|
||||||
|
app:chipEndPadding="6dp"
|
||||||
|
app:chipStartPadding="6dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/yt_shorts" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/filter_livestreams"
|
||||||
|
style="@style/ElevatedFilterChip"
|
||||||
|
android:layout_marginHorizontal="0dp"
|
||||||
|
app:chipEndPadding="6dp"
|
||||||
|
app:chipStartPadding="6dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/livestreams" />
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:text="@string/tooltip_sort" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/sort_radio_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="16dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -55,19 +55,41 @@
|
|||||||
android:animateLayoutChanges="true"
|
android:animateLayoutChanges="true"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/toggle_subs"
|
|
||||||
style="@style/PlayerActionsButton"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:layout_marginHorizontal="14dp"
|
|
||||||
android:layout_marginTop="5dp"
|
<ImageView
|
||||||
android:layout_marginBottom="12dp"
|
android:id="@+id/filter_sort"
|
||||||
android:text="@string/subscriptions"
|
android:layout_width="40dp"
|
||||||
android:textAlignment="viewStart"
|
android:layout_height="40dp"
|
||||||
android:textColor="?colorPrimary"
|
android:src="@drawable/ic_filter_sort"
|
||||||
app:drawableEndCompat="@drawable/ic_arrow_up_down"
|
android:contentDescription="@string/tooltip_filter"
|
||||||
app:drawableTint="?colorPrimary" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="7dp"
|
||||||
|
android:alpha="0.7"/>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/toggle_subs"
|
||||||
|
style="@style/PlayerActionsButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/filter_sort"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:text="@string/subscriptions"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="?colorPrimary"
|
||||||
|
app:drawableEndCompat="@drawable/ic_arrow_up_down"
|
||||||
|
app:drawableTint="?colorPrimary" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/sub_channels_container"
|
android:id="@+id/sub_channels_container"
|
||||||
@ -90,39 +112,6 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="5dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/filterTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:paddingHorizontal="10dp"
|
|
||||||
android:text="@string/all"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:tooltipText="@string/tooltip_filter"
|
|
||||||
app:drawableEndCompat="@drawable/ic_filter" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sortTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginEnd="5dp"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:paddingHorizontal="10dp"
|
|
||||||
android:text="@string/most_recent"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:tooltipText="@string/tooltip_sort"
|
|
||||||
app:drawableEndCompat="@drawable/ic_sort" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user