Fix bugs
Fix bugs with playback & edge-to-edge.
This commit is contained in:
parent
fcebfda406
commit
71cd15bbf7
13 changed files with 156 additions and 140 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
95
app/src/main/java/org/oxycblt/auxio/ui/EdgeUtils.kt
Normal file
95
app/src/main/java/org/oxycblt/auxio/ui/EdgeUtils.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue