Roll custom fast scroller

Drop the old IndicatorFastScroll library from Auxio and replace it with a hyper-specialized variant designed specifically for Auxio.
This not only eliminates a source of hacks/problems/bloat, it also removes a dependency on jcenter (Which is shutting down soon)
This commit is contained in:
OxygenCobalt 2021-03-22 16:00:12 -06:00
parent 816dc2394a
commit 02fed16c31
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
11 changed files with 376 additions and 229 deletions

View file

@ -97,9 +97,6 @@ dependencies {
// Material // Material
implementation 'com.google.android.material:material:1.3.0' implementation 'com.google.android.material:material:1.3.0'
// Fast-Scroll
implementation 'com.reddit:indicator-fast-scroll:1.3.0'
// Dialogs // Dialogs
implementation 'com.afollestad.material-dialogs:core:3.3.0' implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:files:3.3.0' implementation 'com.afollestad.material-dialogs:files:3.3.0'

View file

@ -1,119 +0,0 @@
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.View
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
}
}
visibility = View.INVISIBLE
isActivated = false
post {
visibility = View.VISIBLE
}
}
/**
* 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 { _, event ->
scrollView.onTouchEvent(event)
scrollView.performClick()
val action = event.actionMasked
val actionValid = action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL
isActivated = if (actionValid) {
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
}
}

View file

@ -0,0 +1,81 @@
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.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.core.widget.TextViewCompat
import androidx.databinding.DataBindingUtil
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ViewScrollThumbBinding
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.inflater
/**
* The companion thumb for [FastScrollView]. This does not need any setup, instead pass it as an
* argument to [FastScrollView.setup].
* This code is fundamentally an adaptation of Reddit's IndicatorFastScroll, targeted towards
* Auxio specifically. Check them out here: https://github.com/reddit/IndicatorFastScroll/
* @author OxygenCobalt
*/
class FastScrollThumb @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = -1
) : ConstraintLayout(context, attrs, defStyleAttr) {
private val thumbAnim: SpringAnimation
private val binding = DataBindingUtil.inflate<ViewScrollThumbBinding>(
context.inflater, R.layout.view_scroll_thumb, this, true
)
init {
val accent = Accent.get().getStateList(context)
binding.thumbLayout.apply {
backgroundTintList = accent
// Workaround for API 21 tint bug
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
(background as GradientDrawable).apply {
mutate()
color = accent
}
}
}
binding.thumbText.apply {
isVisible = true
TextViewCompat.setTextAppearance(this, R.style.TextAppearance_ThumbIndicator)
}
thumbAnim = SpringAnimation(binding.thumbLayout, DynamicAnimation.TRANSLATION_Y).apply {
spring = SpringForce().also {
it.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
}
}
visibility = View.INVISIBLE
isActivated = false
post {
visibility = View.VISIBLE
}
}
/**
* Make the thumb jump to a new position and update its text to the given [indicator].
* This is not meant for use outside of the main [FastScrollView] code, don't use it.
*/
fun jumpTo(indicator: FastScrollView.Indicator, centerY: Int) {
binding.thumbText.text = indicator.char.toString()
thumbAnim.animateToFinalPosition(
centerY.toFloat() - (binding.thumbLayout.measuredHeight / 2)
)
}
}

View file

@ -0,0 +1,217 @@
package org.oxycblt.auxio.songs
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.widget.TextViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.resolveAttr
import org.oxycblt.auxio.ui.toColor
import kotlin.math.ceil
import kotlin.math.min
/**
* A view that allows for quick scrolling through a [RecyclerView] with many items. Unlike other
* fast-scrollers, this one displays indicators instead of simply a scroll bar.
* This code is fundamentally an adaptation of Reddit's IndicatorFastScroll, targeted towards
* Auxio specifically. Check them out here: https://github.com/reddit/IndicatorFastScroll/
* @author OxygenCobalt
*/
class FastScrollView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = -1
) : LinearLayout(context, attrs, defStyleAttr) {
// --- BASIC SETUP ---
private var mRecycler: RecyclerView? = null
private var mThumb: FastScrollThumb? = null
private var mGetItem: ((Int) -> Char)? = null
// --- INDICATORS ---
/** Representation of a single Indicator character in the view */
data class Indicator(val char: Char, val pos: Int)
private var indicators = listOf<Indicator>()
private val indicatorText: TextView
private val activeColor = Accent.get().color.toColor(context)
private val inactiveColor = android.R.attr.textColorSecondary.resolveAttr(context)
// --- STATE ---
private var hasPostedItemUpdate = false
private var lastPos = -1
init {
isFocusableInTouchMode = true
isClickable = true
gravity = Gravity.CENTER
val textPadding = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 4F, resources.displayMetrics
)
// Making this entire view a TextView will cause distortions due to the touch calculations
// using a height that is not wrapped to the text.
indicatorText = AppCompatTextView(context).apply {
gravity = Gravity.CENTER
includeFontPadding = false
TextViewCompat.setTextAppearance(this, R.style.TextAppearance_FastScroll)
setLineSpacing(textPadding, lineSpacingMultiplier)
setTextColor(inactiveColor)
}
addView(indicatorText)
}
/**
* Set up this view with a [RecyclerView] and a corresponding [FastScrollThumb].
*/
fun setup(recycler: RecyclerView, thumb: FastScrollThumb, getItem: (Int) -> Char) {
check(mRecycler == null) { "Only set up this view once." }
mRecycler = recycler
mThumb = thumb
mGetItem = getItem
postIndicatorUpdate()
}
// --- INDICATOR UPDATES ---
private fun postIndicatorUpdate() {
if (!hasPostedItemUpdate) {
hasPostedItemUpdate = true
post {
val recycler = requireNotNull(mRecycler)
if (recycler.isAttachedToWindow && recycler.adapter != null) {
updateIndicators()
}
hasPostedItemUpdate = false
}
}
}
private fun updateIndicators() {
val recycler = requireNotNull(mRecycler)
val getItem = requireNotNull(mGetItem)
indicators = 0.until(recycler.adapter!!.itemCount).mapNotNull { pos ->
Indicator(getItem(pos), pos)
}.distinctBy { it.char }
val textHeight = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 14F, resources.displayMetrics
)
// If the scroller size is too small to contain all the entries, truncate entries
// so that the fast scroller entries fit.
val maxEntries = height / textHeight
if (indicators.size > maxEntries.toInt()) {
val truncateInterval = ceil(indicators.size / maxEntries).toInt()
check(truncateInterval > 1) {
"Needed to truncate, but truncateInterval was 1 or lower anyway"
}
logD("More entries than screen space, truncating by $truncateInterval.")
indicators = indicators.filterIndexed { index, _ ->
index % truncateInterval == 0
}
}
indicatorText.apply {
tag = indicators
text = indicators.joinToString("\n") { it.char.toString() }
}
}
// --- TOUCH ---
@Suppress("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
performClick()
val success = handleTouch(event.action, event.y.toInt())
// Depending on the results, update the visibility of the thumb and the pressed state of
// this view.
isPressed = success
mThumb?.isActivated = success
return success
}
@Suppress("UNCHECKED_CAST")
private fun handleTouch(action: Int, touchY: Int): Boolean {
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
indicatorText.setTextColor(inactiveColor)
lastPos = -1
return false
}
if (touchY in (indicatorText.top until indicatorText.bottom)) {
val textHeight = indicatorText.height / indicators.size
val indicatorIndex = min(
(touchY - indicatorText.top) / textHeight, indicators.lastIndex
)
val centerY = y.toInt() + (textHeight / 2) + (indicatorIndex * textHeight)
val touchedIndicator = indicators[indicatorIndex]
selectIndicator(touchedIndicator, centerY)
return true
}
return false
}
private fun selectIndicator(indicator: Indicator, indicatorCenterY: Int) {
if (indicator.pos != lastPos) {
lastPos = indicator.pos
indicatorText.setTextColor(activeColor)
// Stop any scroll momentum and snap-scroll to the position
mRecycler?.apply {
stopScroll()
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
indicator.pos, 0
)
}
mThumb?.jumpTo(indicator, indicatorCenterY)
performHapticFeedback(
if (Build.VERSION.SDK_INT >= 27) {
// Dragging across a scroller is closer to moving a text handle
HapticFeedbackConstants.TEXT_HANDLE_MOVE
} else {
HapticFeedbackConstants.KEYBOARD_TAP
}
)
}
}
}

View file

@ -1,29 +1,21 @@
package org.oxycblt.auxio.songs package org.oxycblt.auxio.songs
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.TypedValue
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.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager 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 import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentSongsBinding import org.oxycblt.auxio.databinding.FragmentSongsBinding
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel 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.canScroll
import org.oxycblt.auxio.ui.fixAnimInfoLeak
import org.oxycblt.auxio.ui.getSpans import org.oxycblt.auxio.ui.getSpans
import org.oxycblt.auxio.ui.newMenu import org.oxycblt.auxio.ui.newMenu
import kotlin.math.ceil
/** /**
* A [Fragment] that shows a list of all songs on the device. * A [Fragment] that shows a list of all songs on the device.
@ -73,75 +65,21 @@ class SongsFragment : Fragment() {
} }
} }
binding.songFastScroll.setup(binding.songRecycler, binding.songFastScrollThumb) binding.songFastScroll.setup(binding.songRecycler, binding.songFastScrollThumb) { pos ->
val char = musicStore.songs[pos].name.first
if (char.isDigit()) '#' else char
}
logD("Fragment created.") logD("Fragment created.")
return binding.root return binding.root
} }
/** override fun onDestroyView() {
* Perform the (Frustratingly Long and Complicated) FastScrollerView setup. super.onDestroyView()
* TODO: Roll FastScrollerView yourself and eliminate its dependency, you're already customizing it enough as it is.
*/
private fun FastScrollerView.setup(recycler: RecyclerView, thumb: CobaltScrollThumb) {
var truncateInterval: Int = -1
val indicatorTextSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 14F,
resources.displayMetrics
)
// API 22 and below don't support the state color, so just use the accent. fixAnimInfoLeak()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
textColor = Accent.get().getStateList(requireContext())
}
setupWithRecyclerView(
recycler,
{ pos ->
val char = musicStore.songs[pos].name.first
FastScrollItemIndicator.Text(
// Use "#" if the character is a digit, also has the nice side-effect of
// truncating extra numbers.
if (char.isDigit()) "#" else char.toString()
)
},
null, false
)
showIndicator = { _, i, total ->
if (truncateInterval == -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()) {
truncateInterval = ceil(total / maxEntries).toInt()
check(truncateInterval > 1) {
"Needed to truncate, but truncateInterval was 1 or lower anyway"
}
logD("More entries than screen space, truncating by $truncateInterval.")
} else {
truncateInterval = 1
}
}
// Any items that need to be truncated will be hidden
(i % truncateInterval) == 0
}
addIndicatorCallback { _, _, pos ->
recycler.apply {
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, 0)
stopScroll()
}
}
thumb.setup(this)
} }
/** /**

View file

@ -10,6 +10,7 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build import android.os.Build
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
@ -23,8 +24,6 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton 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.R
import org.oxycblt.auxio.logE import org.oxycblt.auxio.logE
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -129,6 +128,24 @@ fun Int.toDrawable(context: Context) = ContextCompat.getDrawable(context, this)
*/ */
fun Int.toAnimDrawable(context: Context) = toDrawable(context) as AnimatedVectorDrawable fun Int.toAnimDrawable(context: Context) = toDrawable(context) as AnimatedVectorDrawable
/**
* Resolve this int into a color as if it was an attribute
*/
fun Int.resolveAttr(context: Context): Int {
// Convert the attribute into its color
val resolvedAttr = TypedValue()
context.theme.resolveAttribute(this, resolvedAttr, true)
// Then convert it to a proper color
val color = if (resolvedAttr.resourceId != 0) {
resolvedAttr.resourceId
} else {
resolvedAttr.data
}
return color.toColor(context)
}
/** /**
* Create a [Toast] from a [String] * Create a [Toast] from a [String]
* @param context [Context] required to create the toast * @param context [Context] required to create the toast
@ -137,22 +154,6 @@ fun String.createToast(context: Context) {
Toast.makeText(context.applicationContext, this, Toast.LENGTH_SHORT).show() 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 --- // --- CONFIGURATION ---
/** /**
@ -253,8 +254,8 @@ private fun isSystemBarOnBottom(activity: Activity): Boolean {
// --- HACKY NIGHTMARES --- // --- HACKY NIGHTMARES ---
/** /**
* Use reflection to fix a memory leak in the [Fragment] source code where the focused view will * Use ***REFLECTION*** to fix a memory leak in the [Fragment] source code where the focused view
* never be cleared. I can't believe I have to do this. * will never be cleared. I can't believe I have to do this.
*/ */
fun Fragment.fixAnimInfoLeak() { fun Fragment.fixAnimInfoLeak() {
try { try {

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_pressed="true" />
<item android:color="?android:attr/textColorSecondary" />
</selector>

View file

@ -31,7 +31,7 @@
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" app:layout_constraintTop_toBottomOf="@+id/song_toolbar"
tools:listitem="@layout/item_song" /> tools:listitem="@layout/item_song" />
<com.reddit.indicatorfastscroll.FastScrollerView <org.oxycblt.auxio.songs.FastScrollView
android:id="@+id/song_fast_scroll" android:id="@+id/song_fast_scroll"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_height="0dp"
@ -39,7 +39,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" /> app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />
<org.oxycblt.auxio.songs.CobaltScrollThumb <org.oxycblt.auxio.songs.FastScrollThumb
android:id="@+id/song_fast_scroll_thumb" android:id="@+id/song_fast_scroll_thumb"
android:layout_width="@dimen/width_thumb_view" android:layout_width="@dimen/width_thumb_view"
android:layout_height="0dp" android:layout_height="0dp"

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:layout_height="match_parent"
tools:layout_width="@dimen/fast_scroller_thumb_size"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<FrameLayout
android:id="@+id/thumb_layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/thumb_circle"
android:elevation="@dimen/fast_scroller_thumb_elevation"
android:stateListAnimator="@animator/fast_scroll_thumb"
app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/thumb_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:text="A" />
</FrameLayout>
</merge>
</layout>

View file

@ -16,7 +16,6 @@
<item name="popupMenuStyle">@style/Widget.CustomPopup</item> <item name="popupMenuStyle">@style/Widget.CustomPopup</item>
<item name="colorControlNormal">@color/control_color</item> <item name="colorControlNormal">@color/control_color</item>
<item name="alertDialogTheme">@style/Theme.CustomDialog</item> <item name="alertDialogTheme">@style/Theme.CustomDialog</item>
<item name="indicatorFastScrollerStyle">@style/FastScrollTheme</item>
<item name="colorControlHighlight">@color/selection_color</item> <item name="colorControlHighlight">@color/selection_color</item>
<item name="colorControlActivated">?attr/colorPrimary</item> <item name="colorControlActivated">?attr/colorPrimary</item>
<item name="cornerRadius">0dp</item> <item name="cornerRadius">0dp</item>
@ -99,15 +98,10 @@
<item name="android:fontFamily">@font/inter_exbold</item> <item name="android:fontFamily">@font/inter_exbold</item>
</style> </style>
<!-- Fast scroll theme -->
<style name="FastScrollTheme" parent="Widget.IndicatorFastScroll.FastScroller">
<item name="android:textAppearance">@style/TextAppearance.FastScroll</item>
<item name="android:textColor">@color/color_scroll_tints</item>
</style>
<!-- Fast scroll text appearance --> <!-- Fast scroll text appearance -->
<style name="TextAppearance.FastScroll" parent="TextAppearance.AppCompat.Body2"> <style name="TextAppearance.FastScroll" parent="TextAppearance.AppCompat.Body2">
<item name="android:fontFamily">@font/inter_semibold</item> <item name="android:fontFamily">@font/inter_semibold</item>
<item name="android:lineSpacingExtra">@dimen/padding_tiny</item>
</style> </style>
<!-- Fast scroll thumb appearance --> <!-- Fast scroll thumb appearance -->

View file

@ -5,8 +5,15 @@ buildscript {
repositories { repositories {
google() google()
jcenter() // TODO: Remove JCenter when Exoplayer migrates
mavenCentral() mavenCentral()
// TODO: Eliminate Exoplayer when it migrates to GMaven
jcenter {
content {
includeGroup("org.jetbrains.trove4j")
includeGroup("com.google.android.exoplayer")
}
}
} }
dependencies { dependencies {
@ -22,8 +29,14 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() google()
jcenter()
mavenCentral() mavenCentral()
jcenter {
content {
includeGroup("org.jetbrains.trove4j")
includeGroup("com.google.android.exoplayer")
}
}
} }
} }