Fix bugs with playback & edge-to-edge.
This commit is contained in:
OxygenCobalt 2020-12-16 16:56:26 -07:00
parent fcebfda406
commit 71cd15bbf7
No known key found for this signature in database
GPG key ID: 12BA34F9BCFEADDA
13 changed files with 156 additions and 140 deletions

View file

@ -53,8 +53,6 @@ class MainActivity : AppCompatActivity() {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private fun doEdgeToEdgeSetup(binding: ActivityMainBinding) { private fun doEdgeToEdgeSetup(binding: ActivityMainBinding) {
// TODO: Add landscape edge-to-edge support
window?.apply { window?.apply {
statusBarColor = Color.TRANSPARENT statusBarColor = Color.TRANSPARENT

View file

@ -8,6 +8,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
@ -84,8 +85,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
} }
// Make ellipsizing of song title work // Make ellipsizing of song title work
// Disabled until I can figure out why marquee causes a memory leak. binding.playbackSong.isSelected = true
// binding.playbackSong.isSelected = true
binding.playbackSeekBar.setOnSeekBarChangeListener(this) binding.playbackSeekBar.setOnSeekBarChangeListener(this)
@ -200,6 +200,13 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
return binding.root return binding.root
} }
override fun onStop() {
super.onStop()
// Stop the marqueeing of the song name to prevent a weird memory leak
requireView().findViewById<TextView>(R.id.playback_song).isSelected = false
}
// Seeking callbacks // Seeking callbacks
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) { if (fromUser) {

View file

@ -15,6 +15,7 @@ import org.oxycblt.auxio.logE
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DiffCallback import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder
@ -29,7 +30,7 @@ import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder
*/ */
class QueueAdapter( class QueueAdapter(
private val touchHelper: ItemTouchHelper, private val touchHelper: ItemTouchHelper,
private val onHeaderAction: () -> Unit private val playbackModel: PlaybackViewModel,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var data = mutableListOf<BaseModel>() private var data = mutableListOf<BaseModel>()
private var listDiffer = AsyncListDiffer(this, DiffCallback()) private var listDiffer = AsyncListDiffer(this, DiffCallback())
@ -51,12 +52,15 @@ class QueueAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) { return when (viewType) {
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context) HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
QUEUE_ITEM_TYPE -> QueueSongViewHolder(
ItemQueueSongBinding.inflate(LayoutInflater.from(parent.context))
)
USER_QUEUE_HEADER_ITEM_TYPE -> UserQueueHeaderViewHolder( USER_QUEUE_HEADER_ITEM_TYPE -> UserQueueHeaderViewHolder(
parent.context, ItemActionHeaderBinding.inflate(LayoutInflater.from(parent.context)) parent.context, ItemActionHeaderBinding.inflate(LayoutInflater.from(parent.context))
) )
QUEUE_ITEM_TYPE -> QueueSongViewHolder(
ItemQueueSongBinding.inflate(LayoutInflater.from(parent.context))
)
else -> error("Someone messed with the ViewHolder item types.") else -> error("Someone messed with the ViewHolder item types.")
} }
} }
@ -159,7 +163,7 @@ class QueueAdapter(
setImageResource(R.drawable.ic_clear) setImageResource(R.drawable.ic_clear)
setOnClickListener { setOnClickListener {
onHeaderAction() playbackModel.clearUserQueue()
} }
} }
} }

View file

@ -17,9 +17,7 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.ui.isInIrregularLandscapeMode
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.isSystemBarOnBottom
/** /**
* A [Fragment] that contains both the user queue and the next queue, with the ability to * A [Fragment] that contains both the user queue and the next queue, with the ability to
@ -38,34 +36,20 @@ class QueueFragment : Fragment() {
): View { ): View {
val binding = FragmentQueueBinding.inflate(inflater) val binding = FragmentQueueBinding.inflate(inflater)
val settingsManager = SettingsManager.getInstance()
val callback = QueueDragCallback(playbackModel) val callback = QueueDragCallback(playbackModel)
val helper = ItemTouchHelper(callback) val helper = ItemTouchHelper(callback)
val queueAdapter = QueueAdapter(helper) { val queueAdapter = QueueAdapter(helper, playbackModel)
playbackModel.clearUserQueue()
}
callback.addQueueAdapter(queueAdapter) callback.addQueueAdapter(queueAdapter)
// --- UI SETUP --- // --- UI SETUP ---
// Band-aid that fixes a bug with landscape edge-to-edge where the queue drag buttons
// will be behind the status bar.
if (settingsManager.edgeEnabled) {
if (isLandscape(resources) && !isSystemBarOnBottom(requireActivity())) {
binding.root.rootView.fitsSystemWindows = true
}
}
binding.queueToolbar.apply { binding.queueToolbar.apply {
setNavigationOnClickListener { setNavigationOnClickListener {
findNavController().navigateUp() findNavController().navigateUp()
} }
// Since QueueFragment doesn't fit system windows, inset padding needs to be if (!requireActivity().isInIrregularLandscapeMode()) {
// artificially applied to the Toolbar so that it fits on the main window AND
// so that the elevation doesn't show on the top.
if (!binding.root.rootView.fitsSystemWindows) {
setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets -> setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets ->
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).top insets.getInsets(WindowInsets.Type.systemBars()).top
@ -79,6 +63,8 @@ class QueueFragment : Fragment() {
insets insets
} }
} else {
binding.root.fitsSystemWindows = true
} }
} }

View file

@ -430,6 +430,8 @@ class PlaybackStateManager private constructor() {
logD("Shuffling queue with seed $newSeed") logD("Shuffling queue with seed $newSeed")
val lastSong = mQueue[mIndex]
mShuffleSeed = newSeed mShuffleSeed = newSeed
mQueue.shuffle(Random(newSeed)) mQueue.shuffle(Random(newSeed))
@ -437,9 +439,7 @@ class PlaybackStateManager private constructor() {
// If specified, make the current song the first member of the queue. // If specified, make the current song the first member of the queue.
if (keepSong) { if (keepSong) {
mSong?.let { moveQueueItems(mQueue.indexOf(lastSong), 0)
moveQueueItems(mQueue.indexOf(it), 0)
}
} else { } else {
// Otherwise, just start from the zeroth position in the queue. // Otherwise, just start from the zeroth position in the queue.
mSong = mQueue[0] mSong = mQueue[0]
@ -452,9 +452,11 @@ class PlaybackStateManager private constructor() {
private fun resetShuffle() { private fun resetShuffle() {
mShuffleSeed = -1L mShuffleSeed = -1L
val lastSong = mQueue[mIndex]
setupOrderedQueue() setupOrderedQueue()
mIndex = mQueue.indexOf(mSong) mIndex = mQueue.indexOf(lastSong)
forceQueueUpdate() forceQueueUpdate()
} }

View file

@ -0,0 +1,95 @@
@file:Suppress("DEPRECATION")
@file:TargetApi(Build.VERSION_CODES.O_MR1)
package org.oxycblt.auxio.ui
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.content.res.Configuration
import android.graphics.Point
import android.os.Build
import android.util.DisplayMetrics
import android.view.View
import android.view.Window
import android.view.WindowInsetsController
import android.view.WindowManager
import org.oxycblt.auxio.settings.SettingsManager
/**
* Check if we are in the "Irregular" landscape mode [e.g landscape, but nav bar is on the sides]
* Used to disable most of edge-to-edge if that's the case, as I cant get it to work on this mode yet.
* TODO: Make edge-to-edge work in irregular mode
* @return True if we are in the irregular landscape mode, false if not.
*/
fun Activity.isInIrregularLandscapeMode(): Boolean {
return SettingsManager.getInstance().edgeEnabled &&
isLandscape(resources) &&
!isSystemBarOnBottom(this)
}
/**
* Check if the system bars are on the bottom.
* @return If the system bars are on the bottom, false if no.
*/
private fun isSystemBarOnBottom(activity: Activity): Boolean {
val realPoint = Point()
val metrics = DisplayMetrics()
var width = 0
var height = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
activity.display?.let { display ->
display.getRealSize(realPoint)
activity.windowManager.currentWindowMetrics.bounds.also {
width = it.width()
height = it.height()
}
}
} else {
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).apply {
defaultDisplay.getRealSize(realPoint)
defaultDisplay.getMetrics(metrics)
width = metrics.widthPixels
height = metrics.heightPixels
}
}
val config = activity.resources.configuration
val canMove = (width != height && config.smallestScreenWidthDp < 600)
return (!canMove || width < height)
}
/**
* Handle transparent system bars. Adapted from Music Player GO
* (https://github.com/enricocid/Music-Player-GO)
*/
fun Window.handleTransparentSystemBars(config: Configuration) {
fun isNight() = config.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insetsController?.let { controller ->
val appearance = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS or
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
val mask = if (isNight()) 0 else appearance
controller.setSystemBarsAppearance(appearance, mask)
}
} else {
val flags = decorView.systemUiVisibility
decorView.systemUiVisibility =
if (isNight()) {
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() and
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
} else {
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
}
}

View file

@ -1,22 +1,13 @@
package org.oxycblt.auxio.ui package org.oxycblt.auxio.ui
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Point
import android.os.Build
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.util.DisplayMetrics
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.view.Window
import android.view.WindowInsetsController
import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.Toast import android.widget.Toast
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
@ -33,15 +24,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
// Functions for managing UI elements [Not Colors]
object InterfaceUtils {
const val NAV_HIDDEN = -1
const val NAV_ON_LEFT = 0
const val NAV_ON_RIGHT = 1
const val NAV_ON_BOTTOM = 2
}
/** /**
* Apply a text color to a [MenuItem] * Apply a text color to a [MenuItem]
* @param color The text color that should be applied. * @param color The text color that should be applied.
@ -92,75 +74,6 @@ fun Spanned.render(): Spanned {
) )
} }
/**
* Check if the system bars are on the bottom.
* @return If the system bars are on the bottom, false if no.
*/
@Suppress("DEPRECATION")
fun isSystemBarOnBottom(activity: Activity): Boolean {
val realPoint = Point()
val metrics = DisplayMetrics()
var width = 0
var height = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
activity.display?.let { display ->
display.getRealSize(realPoint)
activity.windowManager.currentWindowMetrics.bounds.also {
width = it.width()
height = it.height()
}
}
} else {
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).apply {
defaultDisplay.getRealSize(realPoint)
defaultDisplay.getMetrics(metrics)
width = metrics.widthPixels
height = metrics.heightPixels
}
}
val config = activity.resources.configuration
val canMove = (width != height && config.smallestScreenWidthDp < 600)
return (!canMove || width < height)
}
/**
* Handle transparent system bars. Adapted from Music Player GO
* (https://github.com/enricocid/Music-Player-GO)
*/
@TargetApi(Build.VERSION_CODES.O_MR1)
@Suppress("DEPRECATION")
fun Window.handleTransparentSystemBars(config: Configuration) {
fun isNight() = config.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insetsController?.let { controller ->
val appearance = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS or
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
val mask = if (isNight()) 0 else appearance
controller.setSystemBarsAppearance(appearance, mask)
}
} else {
val flags = decorView.systemUiVisibility
decorView.systemUiVisibility =
if (isNight()) {
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() and
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
} else {
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
}
}
/** /**
* Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment] * Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment]
*/ */

View file

@ -126,11 +126,11 @@
android:nestedScrollingEnabled="false" android:nestedScrollingEnabled="false"
android:overScrollMode="never" android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_song_header" app:layout_constraintTop_toBottomOf="@+id/album_song_header"
tools:itemCount="4" app:spanCount="2"
tools:itemCount="6"
tools:listitem="@layout/item_album_song" /> tools:listitem="@layout/item_album_song" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -120,10 +120,10 @@
android:nestedScrollingEnabled="false" android:nestedScrollingEnabled="false"
android:overScrollMode="never" android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_album_header" app:layout_constraintTop_toBottomOf="@+id/artist_album_header"
app:spanCount="2"
tools:itemCount="4" tools:itemCount="4"
tools:listitem="@layout/item_album" /> tools:listitem="@layout/item_album" />

View file

@ -121,10 +121,10 @@
android:nestedScrollingEnabled="false" android:nestedScrollingEnabled="false"
android:overScrollMode="never" android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/genre_artist_header" app:layout_constraintTop_toBottomOf="@+id/genre_artist_header"
app:spanCount="2"
tools:itemCount="4" tools:itemCount="4"
tools:listitem="@layout/item_artist" /> tools:listitem="@layout/item_artist" />

View file

@ -48,26 +48,36 @@
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar" app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
tools:src="@drawable/ic_song" /> tools:src="@drawable/ic_song" />
<TextView <!-- TextView is wrapped in a container so that marquee doesn't break -->
android:id="@+id/playback_song"
<FrameLayout
android:id="@+id/playback_song_container"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_mid_large" android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginEnd="24dp" android:layout_marginEnd="@dimen/margin_mid_large"
android:ellipsize="end" app:layout_constraintBottom_toTopOf="@+id/playback_artist"
android:focusable="true" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
app:layout_constraintVertical_chainStyle="packed">
<TextView
android:id="@+id/playback_song"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ellipsize="marquee"
android:fontFamily="@font/inter_semibold" android:fontFamily="@font/inter_semibold"
android:marqueeRepeatLimit="marquee_forever"
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}" android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
android:singleLine="true" android:singleLine="true"
android:text="@{song.name}" android:text="@{song.name}"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" /> tools:text="Song Name" />
</FrameLayout>
<TextView <TextView
android:id="@+id/playback_artist" android:id="@+id/playback_artist"
android:layout_width="0dp" android:layout_width="0dp"
@ -83,7 +93,7 @@
app:layout_constraintBottom_toTopOf="@+id/playback_album" app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/playback_cover" app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_song" app:layout_constraintTop_toBottomOf="@+id/playback_song_container"
tools:text="Artist Name" /> tools:text="Artist Name" />
<TextView <TextView
@ -135,7 +145,7 @@
tools:text="11:38" /> tools:text="11:38" />
<TextView <TextView
android:id="@+id/playback_song_duration" android:id="@+id/playback_song_container_duration"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_mid_large" android:layout_marginEnd="@dimen/margin_mid_large"
@ -203,7 +213,7 @@
android:onClick="@{() -> playbackModel.invertShuffleStatus()}" android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle_large" android:src="@drawable/ic_shuffle_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="@+id/playback_song_duration" app:layout_constraintEnd_toEndOf="@+id/playback_song_container_duration"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next" app:layout_constraintStart_toEndOf="@+id/playback_skip_next"
app:layout_constraintTop_toTopOf="@+id/playback_skip_next" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_next" />

View file

@ -56,8 +56,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_mid_large" android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginEnd="@dimen/margin_mid_large" android:layout_marginEnd="@dimen/margin_mid_large"
android:ellipsize="end" android:ellipsize="marquee"
android:fontFamily="@font/inter_semibold" android:fontFamily="@font/inter_semibold"
android:marqueeRepeatLimit="marquee_forever"
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}" android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
android:singleLine="true" android:singleLine="true"
android:text="@{song.name}" android:text="@{song.name}"

View file

@ -28,7 +28,7 @@
<dimen name="size_cover_compact">44dp</dimen> <dimen name="size_cover_compact">44dp</dimen>
<dimen name="size_cover_normal">56dp</dimen> <dimen name="size_cover_normal">56dp</dimen>
<dimen name="size_cover_large">68dp</dimen> <dimen name="size_cover_large">68dp</dimen>
<dimen name="size_cover_mid_huge">120dp</dimen> <dimen name="size_cover_mid_huge">130dp</dimen>
<dimen name="size_cover_huge">260dp</dimen> <dimen name="size_cover_huge">260dp</dimen>
<dimen name="size_play_pause">70dp</dimen> <dimen name="size_play_pause">70dp</dimen>