Unify fast-scroller
Completely unify the fast scroll indicators and the fast scroll thumb into a single view.
This commit is contained in:
parent
cc3d4fb9c6
commit
0a18108419
14 changed files with 112 additions and 205 deletions
|
|
@ -68,6 +68,7 @@ dependencies {
|
||||||
implementation "androidx.fragment:fragment-ktx:1.3.1"
|
implementation "androidx.fragment:fragment-ktx:1.3.1"
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||||
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
|
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ class MusicStore private constructor() {
|
||||||
* Find a song from this instance in a safe manner.
|
* Find a song from this instance in a safe manner.
|
||||||
* Using a normal search of the songs list runs the risk of getting the *wrong* song with
|
* Using a normal search of the songs list runs the risk of getting the *wrong* song with
|
||||||
* the same name, so the album name is also used to fix the above problem.
|
* the same name, so the album name is also used to fix the above problem.
|
||||||
|
* FIXME: Artist names are more unique than album names, use those
|
||||||
* @param name The name of the song
|
* @param name The name of the song
|
||||||
* @param albumName The name of the song's album.
|
* @param albumName The name of the song's album.
|
||||||
* @return The song requested, null if there isnt one.
|
* @return The song requested, null if there isnt one.
|
||||||
|
|
|
||||||
|
|
@ -1,78 +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.View
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
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 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, albeit specialized
|
|
||||||
* towards Auxio. The original library is 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 = ViewScrollThumbBinding.inflate(context.inflater, 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. Do not use it.
|
|
||||||
*/
|
|
||||||
fun jumpTo(indicator: FastScrollView.Indicator, centerY: Int) {
|
|
||||||
binding.thumbText.text = indicator.char.toString()
|
|
||||||
thumbAnim.animateToFinalPosition(
|
|
||||||
centerY.toFloat() - (binding.thumbLayout.measuredHeight / 2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,22 +4,26 @@ import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.widget.LinearLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import android.widget.TextView
|
import androidx.core.view.isVisible
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.dynamicanimation.animation.DynamicAnimation
|
||||||
import androidx.core.widget.TextViewCompat
|
import androidx.dynamicanimation.animation.SpringAnimation
|
||||||
|
import androidx.dynamicanimation.animation.SpringForce
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
import org.oxycblt.auxio.databinding.ViewFastScrollBinding
|
||||||
import org.oxycblt.auxio.logD
|
import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.ui.Accent
|
import org.oxycblt.auxio.ui.Accent
|
||||||
|
import org.oxycblt.auxio.ui.canScroll
|
||||||
|
import org.oxycblt.auxio.ui.inflater
|
||||||
import org.oxycblt.auxio.ui.resolveAttr
|
import org.oxycblt.auxio.ui.resolveAttr
|
||||||
import org.oxycblt.auxio.ui.toColor
|
import org.oxycblt.auxio.ui.toColor
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view that allows for quick scrolling through a [RecyclerView] with many items. Unlike other
|
* A view that allows for quick scrolling through a [RecyclerView] with many items. Unlike other
|
||||||
|
|
@ -32,22 +36,23 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = -1
|
defStyleAttr: Int = -1
|
||||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
// --- BASIC SETUP ---
|
// --- UI ---
|
||||||
|
|
||||||
|
private val binding = ViewFastScrollBinding.inflate(context.inflater, this, true)
|
||||||
|
private val thumbAnim: SpringAnimation
|
||||||
|
|
||||||
|
// --- RECYCLER ---
|
||||||
|
|
||||||
private var mRecycler: RecyclerView? = null
|
private var mRecycler: RecyclerView? = null
|
||||||
private var mThumb: FastScrollThumb? = null
|
|
||||||
private var mGetItem: ((Int) -> Char)? = null
|
private var mGetItem: ((Int) -> Char)? = null
|
||||||
|
|
||||||
// --- INDICATORS ---
|
// --- INDICATORS ---
|
||||||
|
|
||||||
/** Representation of a single Indicator character in the view */
|
private data class Indicator(val char: Char, val pos: Int)
|
||||||
data class Indicator(val char: Char, val pos: Int)
|
|
||||||
|
|
||||||
private var indicators = listOf<Indicator>()
|
private var indicators = listOf<Indicator>()
|
||||||
|
|
||||||
private val indicatorText: TextView
|
|
||||||
private val activeColor = Accent.get().color.toColor(context)
|
private val activeColor = Accent.get().color.toColor(context)
|
||||||
private val inactiveColor = android.R.attr.textColorSecondary.resolveAttr(context)
|
private val inactiveColor = android.R.attr.textColorSecondary.resolveAttr(context)
|
||||||
|
|
||||||
|
|
@ -59,34 +64,21 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
init {
|
init {
|
||||||
isFocusableInTouchMode = true
|
isFocusableInTouchMode = true
|
||||||
isClickable = true
|
isClickable = true
|
||||||
gravity = Gravity.CENTER
|
|
||||||
|
|
||||||
val textPadding = TypedValue.applyDimension(
|
thumbAnim = SpringAnimation(binding.scrollThumb, DynamicAnimation.TRANSLATION_Y).apply {
|
||||||
TypedValue.COMPLEX_UNIT_DIP, 4F, resources.displayMetrics
|
spring = SpringForce().also {
|
||||||
)
|
it.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
||||||
|
}
|
||||||
// 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].
|
* Set up this view with a [RecyclerView] and a corresponding [FastScrollThumb].
|
||||||
*/
|
*/
|
||||||
fun setup(recycler: RecyclerView, thumb: FastScrollThumb, getItem: (Int) -> Char) {
|
fun setup(recycler: RecyclerView, getItem: (Int) -> Char) {
|
||||||
check(mRecycler == null) { "Only set up this view once." }
|
check(mRecycler == null) { "Only set up this view once." }
|
||||||
|
|
||||||
mRecycler = recycler
|
mRecycler = recycler
|
||||||
mThumb = thumb
|
|
||||||
mGetItem = getItem
|
mGetItem = getItem
|
||||||
|
|
||||||
postIndicatorUpdate()
|
postIndicatorUpdate()
|
||||||
|
|
@ -105,6 +97,9 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
updateIndicators()
|
updateIndicators()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide this view if there is nothing to scroll
|
||||||
|
isVisible = recycler.canScroll()
|
||||||
|
|
||||||
hasPostedItemUpdate = false
|
hasPostedItemUpdate = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -140,9 +135,9 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
indicatorText.apply {
|
// Then set it as the unified TextView text, for efficiency purposes.
|
||||||
tag = indicators
|
binding.scrollIndicatorText.text = indicators.joinToString("\n") { indicator ->
|
||||||
text = indicators.joinToString("\n") { it.char.toString() }
|
indicator.char.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,37 +147,38 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
performClick()
|
performClick()
|
||||||
|
|
||||||
val success = handleTouch(event.action, event.y.toInt())
|
val success = handleTouch(event.action, event.y.roundToInt())
|
||||||
|
|
||||||
// Depending on the results, update the visibility of the thumb and the pressed state of
|
// Depending on the results, update the visibility of the thumb and the pressed state of
|
||||||
// this view.
|
// this view.
|
||||||
isPressed = success
|
isPressed = success
|
||||||
mThumb?.isActivated = success
|
binding.scrollThumb.isActivated = success
|
||||||
|
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private fun handleTouch(action: Int, touchY: Int): Boolean {
|
private fun handleTouch(action: Int, touchY: Int): Boolean {
|
||||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
||||||
indicatorText.setTextColor(inactiveColor)
|
binding.scrollIndicatorText.setTextColor(inactiveColor)
|
||||||
lastPos = -1
|
lastPos = -1
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (touchY in (indicatorText.top until indicatorText.bottom)) {
|
// Try to figure out which indicator the pointer has landed on
|
||||||
// Try to roughly caculate which indicator the user is currently touching [Since the
|
if (touchY in (binding.scrollIndicatorText.top until binding.scrollIndicatorText.bottom)) {
|
||||||
val textHeight = indicatorText.height / indicators.size
|
// Get the touch position in regards to the TextView and the rough text height
|
||||||
val indicatorIndex = min(
|
val indicatorTouchY = touchY - binding.scrollIndicatorText.top
|
||||||
(touchY - indicatorText.top) / textHeight, indicators.lastIndex
|
val textHeight = binding.scrollIndicatorText.height / indicators.size
|
||||||
)
|
|
||||||
|
|
||||||
val centerY = y.toInt() + (textHeight / 2) + (indicatorIndex * textHeight)
|
// Use that to calculate the indicator index, if the calculation is
|
||||||
|
// invalid just ignore it.
|
||||||
|
val index = min(indicatorTouchY / textHeight, indicators.lastIndex)
|
||||||
|
|
||||||
val touchedIndicator = indicators[indicatorIndex]
|
// Also calculate the rough center position of the indicator for the scroll thumb
|
||||||
|
val centerY = binding.scrollIndicatorText.y + (textHeight / 2) + (index * textHeight)
|
||||||
|
|
||||||
selectIndicator(touchedIndicator, centerY)
|
selectIndicator(indicators[index], centerY)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -190,20 +186,20 @@ class FastScrollView @JvmOverloads constructor(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectIndicator(indicator: Indicator, indicatorCenterY: Int) {
|
private fun selectIndicator(indicator: Indicator, centerY: Float) {
|
||||||
if (indicator.pos != lastPos) {
|
if (indicator.pos != lastPos) {
|
||||||
lastPos = indicator.pos
|
lastPos = indicator.pos
|
||||||
indicatorText.setTextColor(activeColor)
|
binding.scrollIndicatorText.setTextColor(activeColor)
|
||||||
|
|
||||||
// Stop any scroll momentum and snap-scroll to the position
|
// Stop any scroll momentum and snap-scroll to the position
|
||||||
mRecycler?.apply {
|
mRecycler?.apply {
|
||||||
stopScroll()
|
stopScroll()
|
||||||
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(indicator.pos, 0)
|
||||||
indicator.pos, 0
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mThumb?.jumpTo(indicator, indicatorCenterY)
|
// Update the thumb position/text
|
||||||
|
binding.scrollThumbText.text = indicator.char.toString()
|
||||||
|
thumbAnim.animateToFinalPosition(centerY - (binding.scrollThumb.measuredHeight / 2))
|
||||||
|
|
||||||
performHapticFeedback(
|
performHapticFeedback(
|
||||||
if (Build.VERSION.SDK_INT >= 27) {
|
if (Build.VERSION.SDK_INT >= 27) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ 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.canScroll
|
|
||||||
import org.oxycblt.auxio.ui.fixAnimInfoLeak
|
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
|
||||||
|
|
@ -55,17 +54,9 @@ class SongsFragment : Fragment() {
|
||||||
if (spans != 1) {
|
if (spans != 1) {
|
||||||
layoutManager = GridLayoutManager(requireContext(), spans)
|
layoutManager = GridLayoutManager(requireContext(), spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
post {
|
|
||||||
if (!canScroll()) {
|
|
||||||
// Disable fast scrolling if there is nothing to scroll
|
|
||||||
binding.songFastScroll.visibility = View.GONE
|
|
||||||
binding.songFastScrollThumb.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.songFastScroll.setup(binding.songRecycler, binding.songFastScrollThumb) { pos ->
|
binding.songFastScroll.setup(binding.songRecycler) { pos ->
|
||||||
val char = musicStore.songs[pos].name.first
|
val char = musicStore.songs[pos].name.first
|
||||||
|
|
||||||
if (char.isDigit()) '#' else char
|
if (char.isDigit()) '#' else char
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ fun Context.getPlural(@PluralsRes pluralsRes: Int, value: Int): String {
|
||||||
* @param T The system service in question.
|
* @param T The system service in question.
|
||||||
* @param serviceClass The service's kotlin class [Java class will be used in function call]
|
* @param serviceClass The service's kotlin class [Java class will be used in function call]
|
||||||
* @return The system service
|
* @return The system service
|
||||||
* @throws IllegalStateException If the system service cannot be retrieved.
|
* @throws IllegalArgumentException If the system service cannot be retrieved.
|
||||||
*/
|
*/
|
||||||
fun <T : Any> Context.getSystemServiceSafe(serviceClass: KClass<T>): T {
|
fun <T : Any> Context.getSystemServiceSafe(serviceClass: KClass<T>): T {
|
||||||
return requireNotNull(ContextCompat.getSystemService(this, serviceClass.java)) {
|
return requireNotNull(ContextCompat.getSystemService(this, serviceClass.java)) {
|
||||||
|
|
@ -218,7 +218,6 @@ fun Activity.isIrregularLandscape(): Boolean {
|
||||||
* Check if the system bars are on the bottom.
|
* Check if the system bars are on the bottom.
|
||||||
* @return If the system bars are on the bottom, false if no.
|
* @return If the system bars are on the bottom, false if no.
|
||||||
*/
|
*/
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
private fun isSystemBarOnBottom(activity: Activity): Boolean {
|
private fun isSystemBarOnBottom(activity: Activity): Boolean {
|
||||||
val realPoint = Point()
|
val realPoint = Point()
|
||||||
val metrics = DisplayMetrics()
|
val metrics = DisplayMetrics()
|
||||||
|
|
@ -236,6 +235,7 @@ private fun isSystemBarOnBottom(activity: Activity): Boolean {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
(activity.getSystemServiceSafe(WindowManager::class)).apply {
|
(activity.getSystemServiceSafe(WindowManager::class)).apply {
|
||||||
defaultDisplay.getRealSize(realPoint)
|
defaultDisplay.getRealSize(realPoint)
|
||||||
defaultDisplay.getMetrics(metrics)
|
defaultDisplay.getMetrics(metrics)
|
||||||
|
|
|
||||||
5
app/src/main/res/drawable/ui_circle.xml
Normal file
5
app/src/main/res/drawable/ui_circle.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
|
@ -39,13 +39,5 @@
|
||||||
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.FastScrollThumb
|
|
||||||
android:id="@+id/song_fast_scroll_thumb"
|
|
||||||
android:layout_width="@dimen/width_thumb_view"
|
|
||||||
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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</layout>
|
</layout>
|
||||||
49
app/src/main/res/layout/view_fast_scroll.xml
Normal file
49
app/src/main/res/layout/view_fast_scroll.xml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout 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">
|
||||||
|
|
||||||
|
<merge
|
||||||
|
tools:layout_height="match_parent"
|
||||||
|
tools:layout_width="match_parent"
|
||||||
|
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/scroll_thumb"
|
||||||
|
android:layout_width="@dimen/size_scroll_thumb"
|
||||||
|
android:layout_height="@dimen/size_scroll_thumb"
|
||||||
|
android:background="@drawable/ui_circle"
|
||||||
|
android:elevation="@dimen/elevation_small"
|
||||||
|
android:backgroundTint="?attr/colorPrimary"
|
||||||
|
android:stateListAnimator="@animator/animator_thumb"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/scroll_indicator_text">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scroll_thumb_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="@dimen/text_size_thumb"
|
||||||
|
android:textColor="?android:attr/windowBackground"
|
||||||
|
android:fontFamily="@font/inter_semibold"
|
||||||
|
tools:text="A" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scroll_indicator_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/inter_semibold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:lineSpacingExtra="@dimen/padding_tiny"
|
||||||
|
android:paddingTop="@dimen/padding_tiny"
|
||||||
|
android:paddingBottom="@dimen/padding_tiny"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="A\nB\n\C\nD\nE" />
|
||||||
|
|
||||||
|
</merge>
|
||||||
|
</layout>
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Animator from IndicatorFastScroll (https://github.com/reddit/IndicatorFastScroll) -->
|
|
||||||
<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/size_scroll_thumb"
|
|
||||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/thumb_layout"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="@drawable/ui_circular_button"
|
|
||||||
android:elevation="@dimen/elevation_small"
|
|
||||||
android:stateListAnimator="@animator/animator_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>
|
|
||||||
|
|
@ -24,11 +24,6 @@
|
||||||
android:name="org.oxycblt.auxio.MainFragment"
|
android:name="org.oxycblt.auxio.MainFragment"
|
||||||
android:label="MainFragment"
|
android:label="MainFragment"
|
||||||
tools:layout="@layout/fragment_main">
|
tools:layout="@layout/fragment_main">
|
||||||
<action
|
|
||||||
android:id="@+id/action_return_to_loading"
|
|
||||||
app:destination="@id/loading_fragment"
|
|
||||||
app:popUpTo="@id/main_fragment"
|
|
||||||
app:popUpToInclusive="true" />
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_go_to_playback"
|
android:id="@+id/action_go_to_playback"
|
||||||
app:destination="@id/playback_fragment"
|
app:destination="@id/playback_fragment"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
<dimen name="size_play_pause">70dp</dimen>
|
<dimen name="size_play_pause">70dp</dimen>
|
||||||
<dimen name="size_play_pause_compact">36dp</dimen>
|
<dimen name="size_play_pause_compact">36dp</dimen>
|
||||||
<dimen name="size_scroll_thumb">32dp</dimen>
|
<dimen name="size_scroll_thumb">48dp</dimen>
|
||||||
<dimen name="size_clear">32dp</dimen>
|
<dimen name="size_clear">32dp</dimen>
|
||||||
|
|
||||||
<dimen name="size_app_icon">60dp</dimen>
|
<dimen name="size_app_icon">60dp</dimen>
|
||||||
|
|
|
||||||
|
|
@ -98,18 +98,6 @@
|
||||||
<item name="android:fontFamily">@font/inter_exbold</item>
|
<item name="android:fontFamily">@font/inter_exbold</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Fast scroll text appearance -->
|
|
||||||
<style name="TextAppearance.FastScroll" parent="TextAppearance.AppCompat.Body2">
|
|
||||||
<item name="android:fontFamily">@font/inter_semibold</item>
|
|
||||||
<item name="android:lineSpacingExtra">@dimen/padding_tiny</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- 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 -->
|
<!-- Style for the general item background -->
|
||||||
<style name="ItemSurroundings">
|
<style name="ItemSurroundings">
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.4.31'
|
ext.kotlin_version = "1.4.31"
|
||||||
ext.navigation_version = "2.3.4"
|
ext.navigation_version = "2.3.4"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
// TODO: Eliminate Exoplayer when it migrates to GMaven
|
|
||||||
jcenter {
|
jcenter {
|
||||||
content {
|
content {
|
||||||
includeGroup("org.jetbrains.trove4j")
|
includeGroup("org.jetbrains.trove4j")
|
||||||
includeGroup("com.google.android.exoplayer")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
classpath "com.android.tools.build:gradle:4.1.3"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
|
||||||
|
|
||||||
|
|
@ -31,9 +29,9 @@ allprojects {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
|
// TODO: Eliminate Exoplayer when it migrates to GMaven
|
||||||
jcenter {
|
jcenter {
|
||||||
content {
|
content {
|
||||||
includeGroup("org.jetbrains.trove4j")
|
|
||||||
includeGroup("com.google.android.exoplayer")
|
includeGroup("com.google.android.exoplayer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue