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 isCurrentlyPlaying = "isCurrentlyPlaying"
|
||||
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_WATCHED_FEED_TIME = "last_watched_feed_time"
|
||||
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"
|
||||
|
||||
/**
|
||||
|
@ -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.db.DatabaseHelper
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.enums.ContentFilter
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
@ -145,12 +146,13 @@ class HomeFragment : Fragment() {
|
||||
}
|
||||
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
|
||||
}
|
||||
|
||||
val allowShorts = ContentFilter.SHORTS.isEnabled()
|
||||
val allowVideos = ContentFilter.VIDEOS.isEnabled()
|
||||
val allowAll = (!allowShorts && !allowVideos)
|
||||
|
||||
var filteredFeed = feed.filter {
|
||||
when (PreferenceHelper.getInt(PreferenceKeys.SELECTED_FEED_FILTER, 0)) {
|
||||
1 -> !it.isShort
|
||||
2 -> it.isShort
|
||||
else -> true
|
||||
}
|
||||
(allowShorts && it.isShort) || (allowVideos && !it.isShort) || allowAll
|
||||
}
|
||||
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
||||
filteredFeed = runBlocking { DatabaseHelper.filterUnwatched(filteredFeed) }
|
||||
|
@ -6,6 +6,8 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
@ -16,15 +18,18 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
||||
import com.github.libretube.db.DatabaseHelper
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.enums.ContentFilter
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
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.SubscriptionChannelAdapter
|
||||
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.PlayerViewModel
|
||||
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.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.google.android.material.chip.Chip
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -57,11 +64,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
||||
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, 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(
|
||||
inflater: LayoutInflater,
|
||||
@ -84,9 +86,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
||||
false
|
||||
)
|
||||
|
||||
// update the text according to the current order and filter
|
||||
binding.sortTV.text = resources.getStringArray(R.array.sortOptions)[selectedSortOrder]
|
||||
binding.filterTV.text = resources.getStringArray(R.array.filterOptions)[selectedFilter]
|
||||
setupSortAndFilter()
|
||||
|
||||
binding.subRefresh.isEnabled = true
|
||||
binding.subProgress.isVisible = true
|
||||
@ -109,30 +109,6 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
||||
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.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() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
@ -258,15 +261,17 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
||||
}
|
||||
|
||||
private fun List<StreamItem>.filterByStatusAndWatchPosition(): List<StreamItem> {
|
||||
|
||||
val streamItems = this.filter {
|
||||
val isLive = (it.duration ?: -1L) < 0L
|
||||
when (selectedFilter) {
|
||||
0 -> true
|
||||
1 -> !it.isShort && !isLive
|
||||
2 -> it.isShort
|
||||
3 -> isLive
|
||||
else -> throw IllegalArgumentException()
|
||||
val isVideo = !it.isShort && !it.isLive
|
||||
|
||||
return@filter when {
|
||||
!ContentFilter.SHORTS.isEnabled() && it.isShort -> false
|
||||
!ContentFilter.VIDEOS.isEnabled() && isVideo -> false
|
||||
!ContentFilter.LIVESTREAMS.isEnabled() && it.isLive -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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,20 +55,42 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/filter_sort"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_filter_sort"
|
||||
android:contentDescription="@string/tooltip_filter"
|
||||
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="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="14dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
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
|
||||
android:id="@+id/sub_channels_container"
|
||||
android:layout_width="match_parent"
|
||||
@ -90,39 +112,6 @@
|
||||
android:layout_height="match_parent"
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
Loading…
x
Reference in New Issue
Block a user