Refactor fast scroll
Completely write my own fast scroller thumb and also redo how the fast scroller is configured in SongsFragment.
This commit is contained in:
parent
a9765d2ad6
commit
917540e626
10 changed files with 225 additions and 143 deletions
|
@ -12,6 +12,7 @@ import coil.request.ImageRequest
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.BaseModel
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
|
@ -53,8 +54,12 @@ fun ImageView.bindGenreImage(genre: Genre) {
|
|||
/**
|
||||
* Custom extension function similar to the stock coil load extensions, but handles whether
|
||||
* to show images and custom fetchers.
|
||||
* @param T Any datatype that inherits [BaseModel]
|
||||
* @param data The data itself
|
||||
* @param error Drawable resource to use when loading failed/should not occur.
|
||||
* @param fetcher Required fetcher that uses [T] as its datatype
|
||||
*/
|
||||
inline fun <reified T : Any> ImageView.load(
|
||||
inline fun <reified T : BaseModel> ImageView.load(
|
||||
data: T,
|
||||
@DrawableRes error: Int,
|
||||
fetcher: Fetcher<T>,
|
||||
|
@ -63,7 +68,6 @@ inline fun <reified T : Any> ImageView.load(
|
|||
|
||||
if (!settingsManager.showCovers) {
|
||||
setImageResource(error)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
private val mPosition = MutableLiveData(0L)
|
||||
|
||||
// Queue
|
||||
private val mQueue = MutableLiveData(mutableListOf<Song>())
|
||||
private val mUserQueue = MutableLiveData(mutableListOf<Song>())
|
||||
private val mQueue = MutableLiveData(listOf<Song>())
|
||||
private val mUserQueue = MutableLiveData(listOf<Song>())
|
||||
private val mIndex = MutableLiveData(0)
|
||||
private val mMode = MutableLiveData(PlaybackMode.ALL_SONGS)
|
||||
|
||||
|
@ -64,9 +64,9 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
val position: LiveData<Long> get() = mPosition
|
||||
|
||||
/** The current queue determined by [mode] and [parent] */
|
||||
val queue: LiveData<MutableList<Song>> get() = mQueue
|
||||
val queue: LiveData<List<Song>> get() = mQueue
|
||||
/** The queue created by the user. */
|
||||
val userQueue: LiveData<MutableList<Song>> get() = mUserQueue
|
||||
val userQueue: LiveData<List<Song>> get() = mUserQueue
|
||||
/** The current [PlaybackMode] that also determines the queue */
|
||||
val mode: LiveData<PlaybackMode> get() = mMode
|
||||
/** Whether playback is originating from the user-generated queue or not */
|
||||
|
@ -451,11 +451,11 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onQueueUpdate(queue: MutableList<Song>) {
|
||||
override fun onQueueUpdate(queue: List<Song>) {
|
||||
mQueue.value = queue
|
||||
}
|
||||
|
||||
override fun onUserQueueUpdate(userQueue: MutableList<Song>) {
|
||||
override fun onUserQueueUpdate(userQueue: List<Song>) {
|
||||
mUserQueue.value = userQueue
|
||||
}
|
||||
|
||||
|
|
|
@ -101,9 +101,9 @@ class PlaybackStateManager private constructor() {
|
|||
/** The current playback progress */
|
||||
val position: Long get() = mPosition
|
||||
/** The current queue determined by [parent] and [mode] */
|
||||
val queue: MutableList<Song> get() = mQueue
|
||||
val queue: List<Song> get() = mQueue
|
||||
/** The queue created by the user. */
|
||||
val userQueue: MutableList<Song> get() = mUserQueue
|
||||
val userQueue: List<Song> get() = mUserQueue
|
||||
/** The current index of the queue */
|
||||
val index: Int get() = mIndex
|
||||
/** The current [PlaybackMode] */
|
||||
|
@ -116,7 +116,7 @@ class PlaybackStateManager private constructor() {
|
|||
val loopMode: LoopMode get() = mLoopMode
|
||||
/** Whether this instance has already been restored */
|
||||
val isRestored: Boolean get() = mIsRestored
|
||||
/** Whether this instance has started playing or not */
|
||||
/** Whether playback has begun in this instance during **PlaybackService's Lifecycle.** */
|
||||
val hasPlayed: Boolean get() = mHasPlayed
|
||||
|
||||
private val settingsManager = SettingsManager.getInstance()
|
||||
|
@ -788,8 +788,8 @@ class PlaybackStateManager private constructor() {
|
|||
fun onSongUpdate(song: Song?) {}
|
||||
fun onParentUpdate(parent: Parent?) {}
|
||||
fun onPositionUpdate(position: Long) {}
|
||||
fun onQueueUpdate(queue: MutableList<Song>) {}
|
||||
fun onUserQueueUpdate(userQueue: MutableList<Song>) {}
|
||||
fun onQueueUpdate(queue: List<Song>) {}
|
||||
fun onUserQueueUpdate(userQueue: List<Song>) {}
|
||||
fun onModeUpdate(mode: PlaybackMode) {}
|
||||
fun onIndexUpdate(index: Int) {}
|
||||
fun onPlayingUpdate(isPlaying: Boolean) {}
|
||||
|
|
|
@ -252,7 +252,11 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
}
|
||||
|
||||
override fun onLoopUpdate(loopMode: LoopMode) {
|
||||
player.setLoopMode(loopMode)
|
||||
player.repeatMode = if (loopMode == LoopMode.NONE) {
|
||||
Player.REPEAT_MODE_OFF
|
||||
} else {
|
||||
Player.REPEAT_MODE_ALL
|
||||
}
|
||||
|
||||
if (!settingsManager.useAltNotifAction) {
|
||||
notification.setLoop(this, loopMode)
|
||||
|
@ -344,27 +348,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
onLoopUpdate(playbackManager.loopMode)
|
||||
onSongUpdate(playbackManager.song)
|
||||
onSeek(playbackManager.position)
|
||||
|
||||
/*
|
||||
Old Manual restore code, restore this if the above causes bugs
|
||||
notification.setParent(this, playbackManager.parent)
|
||||
notification.setPlaying(this, playbackManager.isPlaying)
|
||||
|
||||
if (settingsManager.useAltNotifAction) {
|
||||
notification.setShuffle(this, playbackManager.isShuffling)
|
||||
} else {
|
||||
notification.setLoop(this, playbackManager.loopMode)
|
||||
}
|
||||
|
||||
player.setLoopMode(playbackManager.loopMode)
|
||||
|
||||
playbackManager.song?.let { song ->
|
||||
notification.setMetadata(this, song, settingsManager.colorizeNotif) {}
|
||||
|
||||
player.setMediaItem(MediaItem.fromUri(song.id.toURI()))
|
||||
player.seekTo(playbackManager.position)
|
||||
player.prepare()
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,17 +389,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to transform a [LoopMode] into a player repeat mode
|
||||
*/
|
||||
private fun Player.setLoopMode(mode: LoopMode) {
|
||||
repeatMode = if (mode == LoopMode.NONE) {
|
||||
Player.REPEAT_MODE_OFF
|
||||
} else {
|
||||
Player.REPEAT_MODE_ALL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring the service into the foreground and show the notification, or refresh the notification.
|
||||
*/
|
||||
|
|
112
app/src/main/java/org/oxycblt/auxio/songs/CobaltScrollThumb.kt
Normal file
112
app/src/main/java/org/oxycblt/auxio/songs/CobaltScrollThumb.kt
Normal file
|
@ -0,0 +1,112 @@
|
|||
package org.oxycblt.auxio.songs
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation
|
||||
import androidx.dynamicanimation.animation.SpringAnimation
|
||||
import androidx.dynamicanimation.animation.SpringForce
|
||||
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
||||
import com.reddit.indicatorfastscroll.FastScrollerView
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.ui.Accent
|
||||
import org.oxycblt.auxio.ui.addIndicatorCallback
|
||||
import org.oxycblt.auxio.ui.inflater
|
||||
|
||||
/**
|
||||
* A slimmed-down variant of [com.reddit.indicatorfastscroll.FastScrollerThumbView] designed
|
||||
* specifically for Auxio. Also fixes a memory leak that occurs from a bug fix they
|
||||
* added.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class CobaltScrollThumb @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = -1
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
private val thumbView: ViewGroup
|
||||
private val textView: TextView
|
||||
private val thumbAnim: SpringAnimation
|
||||
|
||||
init {
|
||||
context.inflater.inflate(R.layout.fast_scroller_thumb_view, this, true)
|
||||
|
||||
val accent = Accent.get().getStateList(context)
|
||||
|
||||
thumbView = findViewById<ViewGroup>(R.id.fast_scroller_thumb).apply {
|
||||
textView = findViewById(R.id.fast_scroller_thumb_text)
|
||||
|
||||
backgroundTintList = accent
|
||||
|
||||
// Workaround for API 21 tint bug
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
|
||||
(background as GradientDrawable).apply {
|
||||
mutate()
|
||||
color = accent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textView.apply {
|
||||
isVisible = true
|
||||
TextViewCompat.setTextAppearance(this, R.style.TextAppearance_ThumbIndicator)
|
||||
}
|
||||
|
||||
thumbAnim = SpringAnimation(thumbView, DynamicAnimation.TRANSLATION_Y).apply {
|
||||
spring = SpringForce().also {
|
||||
it.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
||||
}
|
||||
}
|
||||
|
||||
isActivated = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up this view with a [FastScrollerView]. Should only be called once.
|
||||
*/
|
||||
fun setup(scrollView: FastScrollerView) {
|
||||
scrollView.addIndicatorCallback { indicator, centerY, _ ->
|
||||
thumbAnim.animateToFinalPosition(centerY.toFloat() - (thumbView.measuredHeight / 2))
|
||||
|
||||
if (indicator is FastScrollItemIndicator.Text) {
|
||||
textView.text = indicator.text
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ClickableViewAccessibility")
|
||||
scrollView.setOnTouchListener { v, event ->
|
||||
scrollView.onTouchEvent(event)
|
||||
scrollView.performClick()
|
||||
|
||||
val action = event.actionMasked
|
||||
|
||||
// If we arent deselecting the scroll view, determine if we are selecting an item.
|
||||
isActivated = if (
|
||||
action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL
|
||||
) isPointerOnItem(scrollView, event.y.toInt()) else false
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack that determines whether the pointer is currently on the [scrollView] or not.
|
||||
*/
|
||||
private fun isPointerOnItem(scrollView: FastScrollerView, touchY: Int): Boolean {
|
||||
scrollView.children.forEach { child ->
|
||||
if (touchY in (child.top until child.bottom)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
||||
import com.reddit.indicatorfastscroll.FastScrollerView
|
||||
import org.oxycblt.auxio.R
|
||||
|
@ -18,6 +19,7 @@ import org.oxycblt.auxio.logD
|
|||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.Accent
|
||||
import org.oxycblt.auxio.ui.addIndicatorCallback
|
||||
import org.oxycblt.auxio.ui.canScroll
|
||||
import org.oxycblt.auxio.ui.getSpans
|
||||
import org.oxycblt.auxio.ui.newMenu
|
||||
|
@ -57,9 +59,7 @@ class SongsFragment : Fragment() {
|
|||
if (it.itemId == R.id.action_shuffle) {
|
||||
playbackModel.shuffleAll()
|
||||
true
|
||||
}
|
||||
|
||||
false
|
||||
} else false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,114 +82,89 @@ class SongsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
setupFastScroller(binding)
|
||||
binding.songFastScroll.setup(binding.songRecycler, binding.songFastScrollThumb)
|
||||
|
||||
logD("Fragment created.")
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
requireView().rootView.clearFocus()
|
||||
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through the fast scroller setup process.
|
||||
* @param binding Binding required
|
||||
* Perform the (Frustratingly Long and Complicated) FastScrollerView setup.
|
||||
*/
|
||||
private fun setupFastScroller(binding: FragmentSongsBinding) {
|
||||
binding.songFastScroll.apply {
|
||||
var concatInterval = -1
|
||||
private fun FastScrollerView.setup(recycler: RecyclerView, thumb: CobaltScrollThumb) {
|
||||
var concatInterval: Int = -1
|
||||
|
||||
// API 22 and below don't support the state color, so just use the accent.
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
textColor = Accent.get().getStateList(requireContext())
|
||||
// API 22 and below don't support the state color, so just use the accent.
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
textColor = Accent.get().getStateList(requireContext())
|
||||
}
|
||||
|
||||
setupWithRecyclerView(
|
||||
recycler,
|
||||
{ pos ->
|
||||
val char = musicStore.songs[pos].name.first
|
||||
|
||||
// Use "#" if the character is a digit, also has the nice side-effect of
|
||||
// truncating extra numbers.
|
||||
if (char.isDigit()) {
|
||||
FastScrollItemIndicator.Text("#")
|
||||
} else {
|
||||
FastScrollItemIndicator.Text(char.toString())
|
||||
}
|
||||
},
|
||||
null, false
|
||||
)
|
||||
|
||||
showIndicator = { _, i, total ->
|
||||
if (concatInterval == -1) {
|
||||
// If the scroller size is too small to contain all the entries, truncate entries
|
||||
// so that the fast scroller entries fit.
|
||||
val maxEntries = (height / (indicatorTextSize + textPadding))
|
||||
|
||||
if (total > maxEntries.toInt()) {
|
||||
concatInterval = ceil(total / maxEntries).toInt()
|
||||
|
||||
check(concatInterval > 1) {
|
||||
"Needed to truncate, but concatInterval was 1 or lower anyway"
|
||||
}
|
||||
|
||||
logD("More entries than screen space, truncating by $concatInterval.")
|
||||
} else {
|
||||
concatInterval = 1
|
||||
}
|
||||
}
|
||||
|
||||
setupWithRecyclerView(
|
||||
binding.songRecycler,
|
||||
{ pos ->
|
||||
val item = musicStore.songs[pos]
|
||||
// Any items that need to be truncated will be hidden
|
||||
(i % concatInterval) == 0
|
||||
}
|
||||
|
||||
// If the item starts with "the"/"a", then actually use the character after that
|
||||
// as its initial. Yes, this is stupidly western-centric but the code [hopefully]
|
||||
// shouldn't run with other languages.
|
||||
val char: Char = if (item.name.length > 5 &&
|
||||
item.name.startsWith("the ", ignoreCase = true)
|
||||
) {
|
||||
item.name[4].toUpperCase()
|
||||
} else if (item.name.length > 3 &&
|
||||
item.name.startsWith("a ", ignoreCase = true)
|
||||
) {
|
||||
item.name[2].toUpperCase()
|
||||
} else {
|
||||
// If it doesn't begin with that word, then just use the first character.
|
||||
item.name[0].toUpperCase()
|
||||
}
|
||||
addIndicatorCallback { _, _, pos ->
|
||||
recycler.apply {
|
||||
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, 0)
|
||||
|
||||
// Use "#" if the character is a digit, also has the nice side-effect of
|
||||
// truncating extra numbers.
|
||||
if (char.isDigit()) {
|
||||
FastScrollItemIndicator.Text("#")
|
||||
} else {
|
||||
FastScrollItemIndicator.Text(char.toString())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
showIndicator = { _, i, total ->
|
||||
var isGood = true
|
||||
|
||||
if (concatInterval == -1) {
|
||||
// If the scroller size is too small to contain all the entries, truncate entries
|
||||
// so that the fast scroller entries fit.
|
||||
val maxEntries = (height / (indicatorTextSize + textPadding))
|
||||
|
||||
if (total > maxEntries.toInt()) {
|
||||
concatInterval = ceil(total / maxEntries).toInt()
|
||||
|
||||
logD("More entries than screen space, truncating by $concatInterval.")
|
||||
|
||||
check(concatInterval > 1) {
|
||||
"ConcatInterval was one despite truncation being needed"
|
||||
}
|
||||
} else {
|
||||
concatInterval = 1
|
||||
}
|
||||
}
|
||||
|
||||
if ((i % concatInterval) != 0) {
|
||||
isGood = false
|
||||
}
|
||||
|
||||
isGood
|
||||
}
|
||||
|
||||
useDefaultScroller = false
|
||||
|
||||
addIndicatorCallback { pos ->
|
||||
binding.songRecycler.apply {
|
||||
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, 0)
|
||||
|
||||
stopScroll()
|
||||
}
|
||||
stopScroll()
|
||||
}
|
||||
}
|
||||
|
||||
binding.songFastScrollThumb.setupWithFastScroller(binding.songFastScroll)
|
||||
thumb.setup(this)
|
||||
}
|
||||
|
||||
private fun FastScrollerView.addIndicatorCallback(callback: (pos: Int) -> Unit) {
|
||||
itemIndicatorSelectedCallbacks.add(
|
||||
object : FastScrollerView.ItemIndicatorSelectedCallback {
|
||||
override fun onItemIndicatorSelected(
|
||||
indicator: FastScrollItemIndicator,
|
||||
indicatorCenterY: Int,
|
||||
itemPosition: Int
|
||||
) = callback(itemPosition)
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Dumb shortcut for getting the first letter in a string, while regarding certain
|
||||
* semantics when it comes to articles.
|
||||
*/
|
||||
private val String.first: Char get() {
|
||||
// If the name actually starts with "The" or "A", get the character *after* that word.
|
||||
// Yes, this is stupidly english centric but it wont run with other languages.
|
||||
if (length > 5 && startsWith("the ", true)) {
|
||||
return get(4).toUpperCase()
|
||||
}
|
||||
|
||||
if (length > 3 && startsWith("a ", true)) {
|
||||
return get(2).toUpperCase()
|
||||
}
|
||||
|
||||
return get(0).toUpperCase()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
||||
import com.reddit.indicatorfastscroll.FastScrollerView
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.logE
|
||||
|
||||
|
@ -121,6 +123,22 @@ fun String.createToast(context: Context) {
|
|||
Toast.makeText(context.applicationContext, this, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut that allows me to add a indicator callback to [FastScrollerView] without
|
||||
* the nightmarish boilerplate that entails.
|
||||
*/
|
||||
fun FastScrollerView.addIndicatorCallback(
|
||||
callback: (indicator: FastScrollItemIndicator, centerY: Int, pos: Int) -> Unit
|
||||
) {
|
||||
itemIndicatorSelectedCallbacks += object : FastScrollerView.ItemIndicatorSelectedCallback {
|
||||
override fun onItemIndicatorSelected(
|
||||
indicator: FastScrollItemIndicator,
|
||||
indicatorCenterY: Int,
|
||||
itemPosition: Int
|
||||
) = callback(indicator, indicatorCenterY, itemPosition)
|
||||
}
|
||||
}
|
||||
|
||||
// --- CONFIGURATION ---
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />
|
||||
|
||||
<org.oxycblt.auxio.recycler.NoLeakThumbView
|
||||
<org.oxycblt.auxio.songs.CobaltScrollThumb
|
||||
android:id="@+id/song_fast_scroll_thumb"
|
||||
android:layout_width="@dimen/width_thumb_view"
|
||||
android:layout_height="0dp"
|
||||
|
|
|
@ -100,8 +100,8 @@
|
|||
|
||||
<!-- Fast scroll theme -->
|
||||
<style name="FastScrollTheme" parent="Widget.IndicatorFastScroll.FastScroller">
|
||||
<item name="android:textColor">@color/color_scroll_tints</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance.FastScroll</item>
|
||||
<item name="android:textColor">@color/color_scroll_tints</item>
|
||||
</style>
|
||||
|
||||
<!-- Fast scroll text appearance -->
|
||||
|
@ -112,6 +112,7 @@
|
|||
<!-- Fast scroll thumb appearance -->
|
||||
<style name="TextAppearance.ThumbIndicator" parent="TextAppearance.FastScroll">
|
||||
<item name="android:textSize">@dimen/text_size_thumb</item>
|
||||
<item name="android:textColor">?android:attr/windowBackground</item>
|
||||
</style>
|
||||
|
||||
<!-- Style for the general item background -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.4.30'
|
||||
ext.kotlin_version = '1.4.31'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
|
Loading…
Reference in a new issue