Add fast scrolling to SongsFragment
Add a fast-scroll bar to the list of songs in SongsFragment.
This commit is contained in:
parent
38afa8f4d2
commit
3fca28dd20
5 changed files with 127 additions and 19 deletions
|
@ -77,16 +77,21 @@ dependencies {
|
|||
|
||||
// --- THIRD PARTY ---
|
||||
|
||||
// ExoPlayer
|
||||
def exoplayer_version = "2.12.1"
|
||||
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
|
||||
implementation "com.google.android.exoplayer:extension-mediasession:$exoplayer_version"
|
||||
|
||||
// Image loading
|
||||
implementation 'io.coil-kt:coil:0.13.0'
|
||||
|
||||
// Material
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
|
||||
// ExoPlayer
|
||||
def exoplayer_version = "2.12.1"
|
||||
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
|
||||
implementation "com.google.android.exoplayer:extension-mediasession:$exoplayer_version"
|
||||
// Fast-Scroll [Too lazy to make it myself]
|
||||
implementation 'com.reddit:indicator-fast-scroll:1.3.0'
|
||||
|
||||
// --- DEV ---
|
||||
|
||||
// Lint
|
||||
ktlint "com.pinterest:ktlint:0.37.2"
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.recycler.viewholders.SongViewHolder
|
||||
|
||||
class SongAdapter(
|
||||
private val data: List<Song>,
|
||||
val data: List<Song>,
|
||||
private val doOnClick: (data: Song) -> Unit,
|
||||
private val doOnLongClick: (data: Song, view: View) -> Unit
|
||||
) : RecyclerView.Adapter<SongViewHolder>() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.oxycblt.auxio.songs
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
|
@ -8,12 +9,17 @@ import android.view.ViewGroup
|
|||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
||||
import com.reddit.indicatorfastscroll.FastScrollerView
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentSongsBinding
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||
import org.oxycblt.auxio.ui.accent
|
||||
import org.oxycblt.auxio.ui.setupSongActions
|
||||
import org.oxycblt.auxio.ui.toColor
|
||||
|
||||
/**
|
||||
* A [Fragment] that shows a list of all songs on the device. Contains options to search/shuffle
|
||||
|
@ -32,8 +38,17 @@ class SongsFragment : Fragment() {
|
|||
|
||||
val musicStore = MusicStore.getInstance()
|
||||
|
||||
val songAdapter = SongAdapter(
|
||||
musicStore.songs,
|
||||
doOnClick = { playbackModel.playSong(it, PlaybackMode.ALL_SONGS) },
|
||||
doOnLongClick = { data, view ->
|
||||
PopupMenu(requireContext(), view).setupSongActions(
|
||||
data, requireContext(), playbackModel
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: Add option to search songs [Or just make a dedicated tab]
|
||||
// TODO: Fast scrolling?
|
||||
|
||||
// --- UI SETUP ---
|
||||
|
||||
|
@ -45,16 +60,75 @@ class SongsFragment : Fragment() {
|
|||
}
|
||||
|
||||
binding.songRecycler.apply {
|
||||
adapter = SongAdapter(
|
||||
musicStore.songs,
|
||||
doOnClick = { playbackModel.playSong(it, PlaybackMode.ALL_SONGS) },
|
||||
doOnLongClick = { data, view ->
|
||||
PopupMenu(requireContext(), view).setupSongActions(
|
||||
data, requireContext(), playbackModel
|
||||
adapter = songAdapter
|
||||
setHasFixedSize(true)
|
||||
}
|
||||
|
||||
binding.songFastScroll.apply {
|
||||
var hasAddedNumber = false
|
||||
var iters = 0
|
||||
|
||||
setupWithRecyclerView(
|
||||
binding.songRecycler,
|
||||
{ pos ->
|
||||
val item = musicStore.songs[pos]
|
||||
iters++
|
||||
|
||||
var char = item.name[0].toUpperCase()
|
||||
|
||||
// If the item starts with "the"/"a", then actually use the character after that
|
||||
// as its initial. Yes, this is stupidly anglo-centric but the code [hopefully]
|
||||
// shouldn't run with other languages.
|
||||
if (item.name.length > 5 &&
|
||||
item.name.startsWith("the ", ignoreCase = true)
|
||||
) {
|
||||
char = item.name[4].toUpperCase()
|
||||
} else if (item.name.length > 3 &&
|
||||
item.name.startsWith("a ", ignoreCase = true)
|
||||
) {
|
||||
char = item.name[2].toUpperCase()
|
||||
}
|
||||
|
||||
// Check if this song starts with a number, if so, then concat it with a single
|
||||
// "Numeric" item if haven't already.
|
||||
// This check only occurs on the second time the fast scroller is polled for items.
|
||||
if (iters >= musicStore.songs.size) {
|
||||
if (char.isDigit()) {
|
||||
if (!hasAddedNumber) {
|
||||
hasAddedNumber = true
|
||||
} else {
|
||||
return@setupWithRecyclerView null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FastScrollItemIndicator.Text(
|
||||
char.toString()
|
||||
)
|
||||
}
|
||||
)
|
||||
setHasFixedSize(true)
|
||||
|
||||
textAppearanceRes = R.style.TextAppearance_FastScroll
|
||||
textColor = ColorStateList.valueOf(accent.first.toColor(requireContext()))
|
||||
useDefaultScroller = false
|
||||
|
||||
itemIndicatorSelectedCallbacks.add(
|
||||
object : FastScrollerView.ItemIndicatorSelectedCallback {
|
||||
override fun onItemIndicatorSelected(
|
||||
indicator: FastScrollItemIndicator,
|
||||
indicatorCenterY: Int,
|
||||
itemPosition: Int
|
||||
) {
|
||||
val layoutManager = binding.songRecycler.layoutManager
|
||||
as LinearLayoutManager
|
||||
|
||||
layoutManager.scrollToPositionWithOffset(itemPosition, 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
binding.songFastScrollThumb.setupWithFastScroller(this)
|
||||
binding.songFastScrollThumb.textAppearanceRes = R.style.TextAppearance_ThumbIndicator
|
||||
}
|
||||
|
||||
Log.d(this::class.simpleName, "Fragment created.")
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".songs.SongsFragment">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
@ -16,17 +16,38 @@
|
|||
android:layout_height="?android:attr/actionBarSize"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:elevation="@dimen/elevation_normal"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:menu="@menu/menu_songs"
|
||||
app:titleTextAppearance="@style/TextAppearance.Toolbar.Header"
|
||||
app:title="@string/label_all_songs" />
|
||||
app:title="@string/label_all_songs"
|
||||
app:titleTextAppearance="@style/TextAppearance.Toolbar.Header" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/song_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/song_fast_scroll"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar"
|
||||
tools:listitem="@layout/item_song" />
|
||||
|
||||
</LinearLayout>
|
||||
<com.reddit.indicatorfastscroll.FastScrollerView
|
||||
android:id="@+id/song_fast_scroll"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />
|
||||
|
||||
<com.reddit.indicatorfastscroll.FastScrollerThumbView
|
||||
android:id="@+id/song_fast_scroll_thumb"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/song_fast_scroll"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
|
@ -47,6 +47,14 @@
|
|||
<item name="android:popupBackground">@color/background</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.FastScroll" parent="TextAppearance.AppCompat.Body2">
|
||||
<item name="android:fontFamily">@font/inter_semibold</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.ThumbIndicator" parent="TextAppearance.FastScroll">
|
||||
<item name="android:textSize">18sp</item>
|
||||
</style>
|
||||
|
||||
<!--
|
||||
Fix to get QueueFragment to not overlap the Status Bar or Navigation Bar [Currently unused but still here]
|
||||
https://stackoverflow.com/a/57790787/14143986
|
||||
|
|
Loading…
Reference in a new issue