Improve fast-scroll
Fix bugs and improve the UI of the fast-scroller on SongsFragment.
This commit is contained in:
parent
1980dafcff
commit
6a5084beb1
13 changed files with 327 additions and 34 deletions
|
|
@ -88,8 +88,9 @@ dependencies {
|
|||
// Material
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
|
||||
// Fast-Scroll [Too lazy to make it myself]
|
||||
// Fast-Scroll
|
||||
implementation 'com.reddit:indicator-fast-scroll:1.3.0'
|
||||
|
||||
// --- DEV ---
|
||||
|
||||
// Lint
|
||||
|
|
|
|||
165
app/src/main/java/org/oxycblt/auxio/recycler/NoLeakThumbView.kt
Normal file
165
app/src/main/java/org/oxycblt/auxio/recycler/NoLeakThumbView.kt
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
package org.oxycblt.auxio.recycler
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
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.toColor
|
||||
|
||||
/**
|
||||
* A source code copy of [com.reddit.indicatorfastscroll.FastScrollerThumbView] that fixes a
|
||||
* memory leak that occurs from having nested fragments. All credit goes to the authors of
|
||||
* the fast scroll library.
|
||||
* <a href="https://github.com/reddit/IndicatorFastScroll"> Link to repo </a>
|
||||
* @author Reddit, OxygenCobalt
|
||||
*/
|
||||
class NoLeakThumbView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = R.attr.indicatorFastScrollerThumbStyle
|
||||
) : ConstraintLayout(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
),
|
||||
FastScrollerView.ItemIndicatorSelectedCallback {
|
||||
|
||||
private var thumbColor = ColorStateList.valueOf(accent.first.toColor(context))
|
||||
var iconColor = R.color.background.toColor(context)
|
||||
var textAppearanceRes = R.style.TextAppearance_ThumbIndicator
|
||||
var textColor = R.color.background.toColor(context)
|
||||
|
||||
private val thumbView: ViewGroup
|
||||
private val textView: TextView
|
||||
private val iconView: ImageView
|
||||
|
||||
private val isSetup: Boolean get() = (fastScrollerView != null)
|
||||
private var fastScrollerView: FastScrollerView? = null
|
||||
|
||||
private val thumbAnimation: SpringAnimation
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.fast_scroller_thumb_view, this, true)
|
||||
thumbView = findViewById(R.id.fast_scroller_thumb)
|
||||
textView = thumbView.findViewById(R.id.fast_scroller_thumb_text)
|
||||
iconView = thumbView.findViewById(R.id.fast_scroller_thumb_icon)
|
||||
|
||||
applyStyle()
|
||||
|
||||
thumbAnimation = SpringAnimation(thumbView, DynamicAnimation.TRANSLATION_Y).apply {
|
||||
spring = SpringForce().apply {
|
||||
dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
fun setupWithFastScroller(fastScrollerView: FastScrollerView) {
|
||||
check(!isSetup) { "Only set this view's FastScrollerView once!" }
|
||||
this.fastScrollerView = fastScrollerView
|
||||
|
||||
fastScrollerView.itemIndicatorSelectedCallbacks += this
|
||||
|
||||
// FastScrollerView's "onItemIndicatorTouched" [Which I would've used here] is internal,
|
||||
// so instead I just use a setOnTouchListener to get the same-ish effect.
|
||||
fastScrollerView.setOnTouchListener { v, event ->
|
||||
fastScrollerView.onTouchEvent(event)
|
||||
fastScrollerView.performClick()
|
||||
|
||||
if (event.actionMasked in intArrayOf(MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL)) {
|
||||
isActivated = false
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
|
||||
isActivated = isPointerOnItem(fastScrollerView, event.y.toInt())
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack so that I can detect when the pointer is off the FastScrollerView's items
|
||||
* without using onItemIndicatorTouched [Which is internal]
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
private fun isPointerOnItem(fastScrollerView: FastScrollerView, touchY: Int): Boolean {
|
||||
fun View.containsY(y: Int) = y in (top until bottom)
|
||||
|
||||
var consumed = false
|
||||
|
||||
fastScrollerView.apply {
|
||||
children.forEach { view ->
|
||||
if (view.containsY(touchY)) {
|
||||
when (view) {
|
||||
is ImageView -> {
|
||||
consumed = true
|
||||
}
|
||||
is TextView -> {
|
||||
consumed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed
|
||||
}
|
||||
|
||||
private fun applyStyle() {
|
||||
thumbView.backgroundTintList = thumbColor
|
||||
if (Build.VERSION.SDK_INT == 21) {
|
||||
// Workaround for 21 background tint bug
|
||||
(thumbView.background as GradientDrawable).apply {
|
||||
mutate()
|
||||
color = thumbColor
|
||||
}
|
||||
}
|
||||
|
||||
TextViewCompat.setTextAppearance(textView, textAppearanceRes)
|
||||
textView.setTextColor(textColor)
|
||||
iconView.imageTintList = ColorStateList.valueOf(iconColor)
|
||||
}
|
||||
|
||||
override fun onItemIndicatorSelected(
|
||||
indicator: FastScrollItemIndicator,
|
||||
indicatorCenterY: Int,
|
||||
itemPosition: Int
|
||||
) {
|
||||
val thumbTargetY = indicatorCenterY.toFloat() - (thumbView.measuredHeight / 2)
|
||||
thumbAnimation.animateToFinalPosition(thumbTargetY)
|
||||
|
||||
when (indicator) {
|
||||
is FastScrollItemIndicator.Text -> {
|
||||
textView.isVisible = true
|
||||
iconView.isVisible = false
|
||||
|
||||
textView.text = indicator.text
|
||||
}
|
||||
is FastScrollItemIndicator.Icon -> {
|
||||
textView.isVisible = false
|
||||
iconView.isVisible = true
|
||||
|
||||
iconView.setImageResource(indicator.iconRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,13 @@ import androidx.databinding.ViewDataBinding
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.oxycblt.auxio.music.BaseModel
|
||||
|
||||
// ViewHolder abstraction that automates some of the things that are common for all ViewHolders.
|
||||
/**
|
||||
* A [RecyclerView.ViewHolder] that streamlines a lot of the common things across all viewholders.
|
||||
* @property baseBinding Basic [ViewDataBinding] required to set up click listeners & sizing.
|
||||
* @property doOnClick Function that specifies what to do when an item is clicked. Specify null if you want no action to occur.
|
||||
* @property doOnLongClick Function that specifies what to do when an item is long clicked. Specify null if you want no action to occur.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
abstract class BaseViewHolder<T : BaseModel>(
|
||||
private val baseBinding: ViewDataBinding,
|
||||
private val doOnClick: ((data: T) -> Unit)?,
|
||||
|
|
@ -18,6 +24,11 @@ abstract class BaseViewHolder<T : BaseModel>(
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the viewholder with whatever [BaseModel] instance that has been specified.
|
||||
* Will call [onBind] on the inheriting ViewHolder.
|
||||
* @param data Data that the viewholder should be binded with
|
||||
*/
|
||||
fun bind(data: T) {
|
||||
doOnClick?.let { onClick ->
|
||||
baseBinding.root.setOnClickListener {
|
||||
|
|
@ -38,5 +49,9 @@ abstract class BaseViewHolder<T : BaseModel>(
|
|||
baseBinding.executePendingBindings()
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that performs binding operations unique to the inheriting viewholder.
|
||||
* Add any specialized code to an override of this instead of [BaseViewHolder] itself.
|
||||
*/
|
||||
protected abstract fun onBind(data: T)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,38 @@
|
|||
package org.oxycblt.auxio.songs
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.oxycblt.auxio.databinding.ItemBasicSongBinding
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.recycler.viewholders.SongViewHolder
|
||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||
|
||||
class SongsAdapter(
|
||||
private val data: List<Song>,
|
||||
private val doOnClick: (data: Song) -> Unit,
|
||||
private val doOnLongClick: (data: Song, view: View) -> Unit
|
||||
) : RecyclerView.Adapter<SongViewHolder>() {
|
||||
) : RecyclerView.Adapter<SongsAdapter.ViewHolder>() {
|
||||
|
||||
override fun getItemCount(): Int = data.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
|
||||
return SongViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(ItemBasicSongBinding.inflate(LayoutInflater.from(parent.context)))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(data[position])
|
||||
}
|
||||
|
||||
inner class ViewHolder(
|
||||
private val binding: ItemBasicSongBinding
|
||||
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick) {
|
||||
|
||||
override fun onBind(data: Song) {
|
||||
binding.song = data
|
||||
|
||||
binding.songName.requestLayout()
|
||||
binding.songInfo.requestLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package org.oxycblt.auxio.songs
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
|
@ -17,16 +17,14 @@ 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
|
||||
* them.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class SongsFragment : Fragment() {
|
||||
class SongsFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -50,11 +48,13 @@ class SongsFragment : Fragment() {
|
|||
|
||||
// --- UI SETUP ---
|
||||
|
||||
binding.songToolbar.setOnMenuItemClickListener {
|
||||
if (it.itemId == R.id.action_shuffle) {
|
||||
playbackModel.shuffleAll()
|
||||
binding.songToolbar.apply {
|
||||
setOnMenuItemClickListener {
|
||||
if (it.itemId == R.id.action_shuffle) {
|
||||
playbackModel.shuffleAll()
|
||||
}
|
||||
true
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
binding.songRecycler.apply {
|
||||
|
|
@ -69,6 +69,14 @@ class SongsFragment : Fragment() {
|
|||
return binding.root
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun setupFastScroller(binding: FragmentSongsBinding) {
|
||||
val musicStore = MusicStore.getInstance()
|
||||
|
||||
|
|
@ -105,6 +113,8 @@ class SongsFragment : Fragment() {
|
|||
if (char.isDigit()) {
|
||||
if (!hasAddedNumber) {
|
||||
hasAddedNumber = true
|
||||
|
||||
return@setupWithRecyclerView FastScrollItemIndicator.Text("#")
|
||||
} else {
|
||||
return@setupWithRecyclerView null
|
||||
}
|
||||
|
|
@ -117,23 +127,20 @@ class SongsFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
|
||||
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
|
||||
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)
|
||||
}
|
||||
layoutManager.scrollToPositionWithOffset(itemPosition, 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
5
app/src/main/res/color/ui_state_color.xml
Normal file
5
app/src/main/res/color/ui_state_color.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?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>
|
||||
11
app/src/main/res/drawable/ic_settings.xml
Normal file
11
app/src/main/res/drawable/ic_settings.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorPrimary">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@+id/queue_header"
|
||||
tools:layout_editor_absoluteX="0dp"
|
||||
tools:listitem="@layout/item_song" />
|
||||
tools:listitem="@layout/item_basic_song" />
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
android:layout_height="0dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/song_fast_scroll"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar"
|
||||
tools:listitem="@layout/item_song" />
|
||||
tools:listitem="@layout/item_basic_song" />
|
||||
|
||||
<com.reddit.indicatorfastscroll.FastScrollerView
|
||||
android:id="@+id/song_fast_scroll"
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_toolbar" />
|
||||
|
||||
<com.reddit.indicatorfastscroll.FastScrollerThumbView
|
||||
<org.oxycblt.auxio.recycler.NoLeakThumbView
|
||||
android:id="@+id/song_fast_scroll_thumb"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="0dp"
|
||||
|
|
|
|||
70
app/src/main/res/layout/item_basic_song.xml
Normal file
70
app/src/main/res/layout/item_basic_song.xml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".recycler.viewholders.SongViewHolder">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="song"
|
||||
type="org.oxycblt.auxio.music.Song" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ui_ripple"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/padding_medium">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover"
|
||||
android:layout_width="@dimen/size_cover_compact"
|
||||
android:layout_height="@dimen/size_cover_compact"
|
||||
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
||||
app:coverArt="@{song}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_song" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:layout_marginEnd="@dimen/margin_medium"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@{song.name}"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/song_info"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Song Name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:layout_marginEnd="@dimen/margin_medium"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:text="@{@string/format_info(song.album.artist.name, song.album.name)}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_name"
|
||||
tools:text="Artist / Album" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
<string name="label_next_user_queue">Next in Queue</string>
|
||||
<string name="label_channel">Music Playback</string>
|
||||
<string name="label_service_playback">The music playback service for Auxio.</string>
|
||||
<string name="label_settings">Settings</string>
|
||||
|
||||
<!-- Debug Namespace | Debug labels -->
|
||||
<string name="debug_state_saved">State saved</string>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<item name="android:windowBackground">@color/background</item>
|
||||
<item name="android:statusBarColor">@android:color/black</item>
|
||||
<item name="android:fontFamily">@font/inter</item>
|
||||
<item name="indicatorFastScrollerStyle">@style/FastScrollTheme</item>
|
||||
<item name="android:textCursorDrawable">@drawable/ui_cursor</item>
|
||||
<item name="android:fitsSystemWindows">true</item>
|
||||
|
||||
|
|
@ -47,9 +48,13 @@
|
|||
<item name="android:popupBackground">@color/background</item>
|
||||
</style>
|
||||
|
||||
<style name="FastScrollTheme" parent="Widget.IndicatorFastScroll.FastScroller">
|
||||
<item name="android:textColor">@color/ui_state_color</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance.FastScroll</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.FastScroll" parent="TextAppearance.AppCompat.Body2">
|
||||
<item name="android:fontFamily">@font/inter_semibold</item>
|
||||
<item name="android:verticalSpacing">1dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.ThumbIndicator" parent="TextAppearance.FastScroll">
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ allprojects {
|
|||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue