mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 06:10:31 +05:30
Merge pull request #3648 from Bnyro/master
Sort menu for local and private playlist
This commit is contained in:
commit
9cb2cfd6aa
@ -38,6 +38,7 @@ object PreferenceKeys {
|
|||||||
const val ALTERNATIVE_VIDEOS_LAYOUT = "alternative_videos_layout"
|
const val ALTERNATIVE_VIDEOS_LAYOUT = "alternative_videos_layout"
|
||||||
const val NEW_VIDEOS_BADGE = "new_videos_badge"
|
const val NEW_VIDEOS_BADGE = "new_videos_badge"
|
||||||
const val PLAYLISTS_ORDER = "playlists_order"
|
const val PLAYLISTS_ORDER = "playlists_order"
|
||||||
|
const val PLAYLIST_SORT_ORDER = "playlist_sort_order"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance
|
* Instance
|
||||||
|
@ -6,6 +6,7 @@ import android.util.Log
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
@ -22,6 +23,7 @@ import com.github.libretube.api.RetrofitInstance
|
|||||||
import com.github.libretube.api.obj.Playlist
|
import com.github.libretube.api.obj.Playlist
|
||||||
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.IntentData
|
||||||
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.databinding.FragmentPlaylistBinding
|
import com.github.libretube.databinding.FragmentPlaylistBinding
|
||||||
import com.github.libretube.db.DatabaseHolder
|
import com.github.libretube.db.DatabaseHolder
|
||||||
import com.github.libretube.enums.PlaylistType
|
import com.github.libretube.enums.PlaylistType
|
||||||
@ -31,8 +33,10 @@ import com.github.libretube.extensions.serializable
|
|||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.helpers.ImageHelper
|
import com.github.libretube.helpers.ImageHelper
|
||||||
import com.github.libretube.helpers.NavigationHelper
|
import com.github.libretube.helpers.NavigationHelper
|
||||||
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
import com.github.libretube.ui.adapters.PlaylistAdapter
|
import com.github.libretube.ui.adapters.PlaylistAdapter
|
||||||
import com.github.libretube.ui.models.PlayerViewModel
|
import com.github.libretube.ui.models.PlayerViewModel
|
||||||
|
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -58,6 +62,11 @@ class PlaylistFragment : Fragment() {
|
|||||||
|
|
||||||
// view models
|
// view models
|
||||||
private val playerViewModel: PlayerViewModel by activityViewModels()
|
private val playerViewModel: PlayerViewModel by activityViewModels()
|
||||||
|
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.PLAYLIST_SORT_ORDER, 0)
|
||||||
|
set(value) {
|
||||||
|
PreferenceHelper.putInt(PreferenceKeys.PLAYLIST_SORT_ORDER, value)
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -139,6 +148,8 @@ class PlaylistFragment : Fragment() {
|
|||||||
|
|
||||||
binding.playlistInfo.text = getChannelAndVideoString(response, response.videos)
|
binding.playlistInfo.text = getChannelAndVideoString(response, response.videos)
|
||||||
|
|
||||||
|
showPlaylistVideos(response)
|
||||||
|
|
||||||
// show playlist options
|
// show playlist options
|
||||||
binding.optionsMenu.setOnClickListener {
|
binding.optionsMenu.setOnClickListener {
|
||||||
PlaylistOptionsBottomSheet(
|
PlaylistOptionsBottomSheet(
|
||||||
@ -197,9 +208,57 @@ class PlaylistFragment : Fragment() {
|
|||||||
keepQueue = true
|
keepQueue = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
binding.sortMenu.isGone = false
|
||||||
|
binding.sortMenu.setOnClickListener {
|
||||||
|
val sortOptions = resources.getStringArray(R.array.playlistSortOptions)
|
||||||
|
|
||||||
|
BaseBottomSheet().apply {
|
||||||
|
setSimpleItems(sortOptions.toList()) { index ->
|
||||||
|
selectedSortOrder = index
|
||||||
|
showPlaylistVideos(response)
|
||||||
|
}
|
||||||
|
}.show(childFragmentManager)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playlistAdapter = PlaylistAdapter(playlistFeed, playlistId!!, playlistType)
|
withContext(Dispatchers.IO) {
|
||||||
|
// update the playlist thumbnail if bookmarked
|
||||||
|
val playlistBookmark = DatabaseHolder.Database.playlistBookmarkDao().getAll()
|
||||||
|
.firstOrNull { it.playlistId == playlistId }
|
||||||
|
playlistBookmark?.let {
|
||||||
|
if (it.thumbnailUrl != response.thumbnailUrl) {
|
||||||
|
it.thumbnailUrl = response.thumbnailUrl
|
||||||
|
DatabaseHolder.Database.playlistBookmarkDao().update(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showPlaylistVideos(playlist: Playlist) {
|
||||||
|
val videos = if (playlistType == PlaylistType.PUBLIC) playlistFeed
|
||||||
|
else {
|
||||||
|
when (selectedSortOrder) {
|
||||||
|
0, 1 -> {
|
||||||
|
if (playlistType == PlaylistType.LOCAL) playlistFeed.sortedBy {
|
||||||
|
it.url.orEmpty().toInt()
|
||||||
|
} else playlistFeed
|
||||||
|
}
|
||||||
|
2, 3 -> {
|
||||||
|
playlistFeed.sortedBy { it.duration }
|
||||||
|
}
|
||||||
|
4, 5 -> {
|
||||||
|
playlistFeed.sortedBy { it.title }
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException()
|
||||||
|
}.let {
|
||||||
|
if (selectedSortOrder % 2 == 0) it else it.reversed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playlistAdapter = PlaylistAdapter(videos.toMutableList(), playlistId!!, playlistType)
|
||||||
|
binding.playlistRecView.adapter = playlistAdapter
|
||||||
|
|
||||||
// listen for playlist items to become deleted
|
// listen for playlist items to become deleted
|
||||||
playlistAdapter!!.registerAdapterDataObserver(object :
|
playlistAdapter!!.registerAdapterDataObserver(object :
|
||||||
@ -212,12 +271,10 @@ class PlaylistFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.playlistInfo.text =
|
binding.playlistInfo.text = getChannelAndVideoString(playlist, playlistFeed.size)
|
||||||
getChannelAndVideoString(response, playlistFeed.size)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.playlistRecView.adapter = playlistAdapter
|
|
||||||
binding.playlistScrollview.viewTreeObserver.addOnScrollChangedListener {
|
binding.playlistScrollview.viewTreeObserver.addOnScrollChangedListener {
|
||||||
if (_binding?.playlistScrollview?.canScrollVertically(1) == false &&
|
if (_binding?.playlistScrollview?.canScrollVertically(1) == false &&
|
||||||
!isLoading
|
!isLoading
|
||||||
@ -259,20 +316,6 @@ class PlaylistFragment : Fragment() {
|
|||||||
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
|
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
|
||||||
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
|
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
// update the playlist thumbnail if bookmarked
|
|
||||||
val playlistBookmark = DatabaseHolder.Database.playlistBookmarkDao().getAll()
|
|
||||||
.firstOrNull { it.playlistId == playlistId }
|
|
||||||
playlistBookmark?.let {
|
|
||||||
if (it.thumbnailUrl != response.thumbnailUrl) {
|
|
||||||
it.thumbnailUrl = response.thumbnailUrl
|
|
||||||
DatabaseHolder.Database.playlistBookmarkDao().update(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StringFormatInvalid", "StringFormatMatches")
|
@SuppressLint("StringFormatInvalid", "StringFormatMatches")
|
||||||
|
10
app/src/main/res/drawable/ic_sort.xml
Normal file
10
app/src/main/res/drawable/ic_sort.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:autoMirrored="true"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?colorControlNormal"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
<path android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
||||||
|
</vector>
|
@ -53,6 +53,15 @@
|
|||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/sortMenu"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:src="@drawable/ic_sort"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/optionsMenu"
|
android:id="@+id/optionsMenu"
|
||||||
android:layout_width="20dp"
|
android:layout_width="20dp"
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
android:paddingHorizontal="10dp"
|
android:paddingHorizontal="10dp"
|
||||||
android:text="@string/most_recent"
|
android:text="@string/most_recent"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:drawableEndCompat="@drawable/ic_arrow_downward" />
|
app:drawableEndCompat="@drawable/ic_sort" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -286,6 +286,15 @@
|
|||||||
<item>@string/yt_shorts</item>
|
<item>@string/yt_shorts</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="playlistSortOptions">
|
||||||
|
<item>@string/least_recent</item>
|
||||||
|
<item>@string/most_recent</item>
|
||||||
|
<item>@string/duration</item>
|
||||||
|
<item>@string/duration_reversed</item>
|
||||||
|
<item>@string/playlist_name_az</item>
|
||||||
|
<item>@string/playlist_name_za</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="requiredNetwork">
|
<string-array name="requiredNetwork">
|
||||||
<item>@string/network_all</item>
|
<item>@string/network_all</item>
|
||||||
<item>@string/network_wifi</item>
|
<item>@string/network_wifi</item>
|
||||||
|
@ -408,6 +408,10 @@
|
|||||||
<string name="play_automatically_summary">Start playing video automatically when selecting</string>
|
<string name="play_automatically_summary">Start playing video automatically when selecting</string>
|
||||||
<string name="fullscreen_gestures">Enter/exit fullscreen gestures</string>
|
<string name="fullscreen_gestures">Enter/exit fullscreen gestures</string>
|
||||||
<string name="go_to_video">Go to video</string>
|
<string name="go_to_video">Go to video</string>
|
||||||
|
<string name="playlist_name_az">Playlist Name (A-Z)</string>
|
||||||
|
<string name="playlist_name_za">Playlist Name (Z-A)</string>
|
||||||
|
<string name="duration">Duration</string>
|
||||||
|
<string name="duration_reversed">Duration (reversed)</string>
|
||||||
|
|
||||||
<!-- Notification channel strings -->
|
<!-- Notification channel strings -->
|
||||||
<string name="download_channel_name">Download Service</string>
|
<string name="download_channel_name">Download Service</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user