playback: rework view implementations

Rework the playback views to follow the new idioms I want to use for
Auxio.

This change mostly consists of flattening away some of the custom
views, removing databinding, and using a general viewbinding
fragment that I hope to extend to the entire app.
This commit is contained in:
OxygenCobalt 2022-03-21 20:13:06 -06:00
parent e4d4266e35
commit 8f38ed6ee5
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
18 changed files with 394 additions and 360 deletions

View file

@ -21,6 +21,7 @@ import android.content.Context
import android.graphics.Bitmap
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.graphics.drawable.toBitmap
import androidx.databinding.BindingAdapter
import coil.dispose
@ -37,23 +38,28 @@ import org.oxycblt.auxio.music.Song
// --- BINDING ADAPTERS ---
/** Bind the album art for a [song]. */
/** Bind the album cover for a [song]. */
@BindingAdapter("albumArt")
fun ImageView.bindAlbumArt(song: Song?) = load(song, R.drawable.ic_album)
fun ImageView.bindAlbumCover(song: Song?) =
load(song, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the album art for an [album]. */
/** Bind the album cover for an [album]. */
@BindingAdapter("albumArt")
fun ImageView.bindAlbumArt(album: Album?) = load(album, R.drawable.ic_album)
fun ImageView.bindAlbumCover(album: Album?) =
load(album, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the image for an [artist] */
@BindingAdapter("artistImage")
fun ImageView.bindArtistImage(artist: Artist?) = load(artist, R.drawable.ic_artist)
fun ImageView.bindArtistImage(artist: Artist?) =
load(artist, R.drawable.ic_artist, R.string.desc_artist_image)
/** Bind the image for a [genre] */
@BindingAdapter("genreImage")
fun ImageView.bindGenreImage(genre: Genre?) = load(genre, R.drawable.ic_genre)
fun ImageView.bindGenreImage(genre: Genre?) =
load(genre, R.drawable.ic_genre, R.string.desc_genre_image)
fun <T : Music> ImageView.load(music: T?, @DrawableRes error: Int) {
fun <T : Music> ImageView.load(music: T?, @DrawableRes error: Int, @StringRes desc: Int) {
contentDescription = context.getString(desc, music?.resolvedName)
dispose()
load(music) {
error(error)

View file

@ -24,7 +24,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumArt
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.detail.DetailViewModel
@ -127,7 +127,7 @@ class AlbumDetailAdapter(
override fun onBind(data: Album) {
binding.detailCover.apply {
bindAlbumArt(data)
bindAlbumCover(data)
contentDescription = context.getString(R.string.desc_album_cover, data.resolvedName)
}

View file

@ -28,8 +28,10 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.google.android.material.color.MaterialColors
import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.bindSongInfo
import org.oxycblt.auxio.ui.BottomSheetLayout
import org.oxycblt.auxio.util.getAttrColorSafe
import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -99,27 +101,25 @@ class PlaybackBarFragment : Fragment() {
// -- VIEWMODEL SETUP ---
binding.song = playbackModel.song.value
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (song != null) {
binding.song = song
binding.executePendingBindings()
binding.playbackCover.bindAlbumCover(song)
binding.playbackSong.text = song.resolvedName
binding.playbackInfo.bindSongInfo(song)
binding.playbackProgressBar.max = song.seconds.toInt()
}
}
binding.playbackPlayPause.isActivated = playbackModel.isPlaying.value!!
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
binding.playbackPlayPause.isActivated = isPlaying
binding.executePendingBindings()
}
binding.playbackProgressBar.progress = playbackModel.position.value!!.toInt()
playbackModel.position.observe(viewLifecycleOwner) { position ->
binding.playbackProgressBar.progress = playbackModel.seconds.value!!.toInt()
playbackModel.seconds.observe(viewLifecycleOwner) { position ->
binding.playbackProgressBar.progress = position.toInt()
}
binding.executePendingBindings()
return binding.root
}
}

View file

@ -20,19 +20,25 @@ package org.oxycblt.auxio.playback
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.color.MaterialColors
import com.google.android.material.slider.Slider
import kotlin.math.max
import org.oxycblt.auxio.MainFragmentDirections
import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.toDuration
import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.ui.BottomSheetLayout
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.getAttrColorSafe
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.stateList
import org.oxycblt.auxio.util.systemBarInsetsCompat
/**
@ -42,28 +48,25 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
*
* TODO: Handle RTL correctly in the playback buttons
*/
class PlaybackPanelFragment : Fragment() {
class PlaybackPanelFragment :
ViewBindingFragment<FragmentPlaybackPanelBinding>(),
Slider.OnChangeListener,
Slider.OnSliderTouchListener {
private val playbackModel: PlaybackViewModel by activityViewModels()
private val detailModel: DetailViewModel by activityViewModels()
private var lastBinding: FragmentPlaybackPanelBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
override fun onCreateBinding(inflater: LayoutInflater): FragmentPlaybackPanelBinding {
return FragmentPlaybackPanelBinding.inflate(inflater)
}
override fun onBindingCreated(
binding: FragmentPlaybackPanelBinding,
savedInstanceState: Bundle?
): View {
val binding = FragmentPlaybackPanelBinding.inflate(layoutInflater)
) {
val queueItem: MenuItem
// See onDestroyView for why we do this
lastBinding = binding
// --- UI SETUP ---
binding.lifecycleOwner = viewLifecycleOwner
binding.playbackModel = playbackModel
binding.detailModel = detailModel
binding.root.setOnApplyWindowInsetsListener { _, insets ->
val bars = insets.systemBarInsetsCompat
binding.root.updatePadding(top = bars.top, bottom = bars.bottom)
@ -85,20 +88,62 @@ class PlaybackPanelFragment : Fragment() {
queueItem = menu.findItem(R.id.action_queue)
}
// Make marquee of song title work
binding.playbackSong.isSelected = true
binding.playbackSeekBar.onConfirmListener = playbackModel::setPosition
binding.playbackSong.apply {
// Make marquee of the song title work
isSelected = true
setOnClickListener { playbackModel.song.value?.let { detailModel.navToItem(it) } }
}
// Abuse the play/pause FAB (see style definition for more info)
binding.playbackPlayPause.post { binding.playbackPlayPause.stateListAnimator = null }
binding.playbackArtist.setOnClickListener {
playbackModel.song.value?.let { detailModel.navToItem(it.album.artist) }
}
binding.playbackAlbum.setOnClickListener {
playbackModel.song.value?.let { detailModel.navToItem(it.album) }
}
binding.playbackSeekBar.apply {
addOnChangeListener(this@PlaybackPanelFragment)
addOnSliderTouchListener(this@PlaybackPanelFragment)
// Composite a tint list based on the active/inactive colors
trackInactiveTintList =
MaterialColors.compositeARGBWithAlpha(
context.getAttrColorSafe(R.attr.colorSecondary), (255 * 0.2).toInt())
.stateList
}
binding.playbackLoop.setOnClickListener { playbackModel.incrementLoopStatus() }
binding.playbackSkipPrev.setOnClickListener { playbackModel.skipPrev() }
binding.playbackPlayPause.apply {
// Abuse the play/pause FAB (see style definition for more info)
post { binding.playbackPlayPause.stateListAnimator = null }
setOnClickListener { playbackModel.invertPlayingStatus() }
}
binding.playbackSkipNext.setOnClickListener { playbackModel.skipNext() }
binding.playbackShuffle.setOnClickListener { playbackModel.invertShuffleStatus() }
// --- VIEWMODEL SETUP --
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (song != null) {
logD("Updating song display to ${song.rawName}")
binding.song = song
binding.playbackSeekBar.setDuration(song.seconds)
binding.playbackCover.bindAlbumCover(song)
binding.playbackSong.text = song.resolvedName
binding.playbackArtist.text = song.resolvedArtistName
binding.playbackAlbum.text = song.resolvedAlbumName
// Normally if a song had a duration
val seconds = song.seconds
binding.playbackDuration.text = seconds.toDuration(false)
binding.playbackSeekBar.apply {
valueTo = max(seconds, 1L).toFloat()
isEnabled = seconds > 0L
}
}
}
@ -125,8 +170,13 @@ class PlaybackPanelFragment : Fragment() {
}
}
playbackModel.position.observe(viewLifecycleOwner) { pos ->
binding.playbackSeekBar.setProgress(pos)
playbackModel.seconds.observe(viewLifecycleOwner) { pos ->
// Don't update the progress while we are seeking, that will make the SeekBar jump
// around.
if (!binding.playbackSeconds.isActivated) {
binding.playbackSeekBar.value = pos.toFloat()
binding.playbackSeconds.text = pos.toDuration(true)
}
}
playbackModel.nextUp.observe(viewLifecycleOwner) {
@ -146,17 +196,27 @@ class PlaybackPanelFragment : Fragment() {
}
logD("Fragment Created")
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
override fun onDestroyBinding(binding: FragmentPlaybackPanelBinding) {
binding.playbackSong.isSelected = false
binding.playbackSeekBar.removeOnChangeListener(this)
binding.playbackSeekBar.removeOnChangeListener(this)
}
// playbackSong will leak if we don't disable marquee, keep the binding around
// so that we can turn it off when we destroy the view.
lastBinding?.playbackSong?.isSelected = false
lastBinding = null
override fun onStartTrackingTouch(slider: Slider) {
requireBinding().playbackSeconds.isActivated = true
}
override fun onStopTrackingTouch(slider: Slider) {
requireBinding().playbackSeconds.isActivated = false
playbackModel.setPosition(slider.value.toLong())
}
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
if (fromUser) {
requireBinding().playbackSeconds.text = value.toLong().toDuration(true)
}
}
private fun navigateUp() {

View file

@ -1,112 +0,0 @@
/*
* Copyright (c) 2021 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.playback
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.color.MaterialColors
import com.google.android.material.slider.Slider
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ViewSeekBarBinding
import org.oxycblt.auxio.music.toDuration
import org.oxycblt.auxio.util.getAttrColorSafe
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.stateList
/**
* A custom view that bundles together a seekbar with a current duration and a total duration. The
* sub-views are specifically laid out so that the seekbar has an adequate touch height while still
* not having gobs of whitespace everywhere.
*
* TODO: Add smooth seeking [i.e seeking in sub-second values]
* @author OxygenCobalt
*/
@SuppressLint("RestrictedApi")
class PlaybackSeekBar
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0) :
ConstraintLayout(context, attrs, defStyleRes),
Slider.OnChangeListener,
Slider.OnSliderTouchListener {
private val binding = ViewSeekBarBinding.inflate(context.inflater, this, true)
private val isSeeking: Boolean
get() = binding.playbackDurationCurrent.isActivated
var onConfirmListener: ((Long) -> Unit)? = null
init {
binding.seekBar.addOnChangeListener(this)
binding.seekBar.addOnSliderTouchListener(this)
// Override the inactive color so that it lines up with the playback progress bar.
binding.seekBar.trackInactiveTintList =
MaterialColors.compositeARGBWithAlpha(
context.getAttrColorSafe(R.attr.colorSecondary), (255 * 0.2).toInt())
.stateList
}
fun setProgress(seconds: Long) {
// Don't update the progress while we are seeking, that will make the SeekBar jump around.
if (!isSeeking) {
binding.seekBar.value = seconds.toFloat()
binding.playbackDurationCurrent.text = seconds.toDuration(true)
}
}
fun setDuration(seconds: Long) {
if (seconds == 0L) {
// One of two things occurred:
// - Android couldn't get the total duration of the song
// - The duration of the song was so low as to be rounded to zero when converted
// to seconds.
// In either of these cases, the seekbar is more or less useless. Disable it.
logD("Duration is 0, entering disabled state")
binding.seekBar.apply {
valueTo = 1f
isEnabled = false
}
} else {
binding.seekBar.apply {
valueTo = seconds.toFloat()
isEnabled = true
}
}
binding.playbackSongDuration.text = seconds.toDuration(false)
}
override fun onStartTrackingTouch(slider: Slider) {
binding.playbackDurationCurrent.isActivated = true
}
override fun onStopTrackingTouch(slider: Slider) {
binding.playbackDurationCurrent.isActivated = false
onConfirmListener?.invoke(slider.value.toLong())
}
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
if (fromUser) {
// Don't actually seek yet when the user moves the progress bar, as to make our
// player seek during every movement is both inefficient and weird.
binding.playbackDurationCurrent.text = value.toLong().toDuration(true)
}
}
}

View file

@ -58,7 +58,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
private val mIsPlaying = MutableLiveData(false)
private val mIsShuffling = MutableLiveData(false)
private val mLoopMode = MutableLiveData(LoopMode.NONE)
private val mPosition = MutableLiveData(0L)
private val mSeconds = MutableLiveData(0L)
// Queue
private val mNextUp = MutableLiveData(listOf<Song>())
@ -82,8 +82,8 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
val loopMode: LiveData<LoopMode>
get() = mLoopMode
/** The current playback position, in seconds */
val position: LiveData<Long>
get() = mPosition
val seconds: LiveData<Long>
get() = mSeconds
/** The queue, without the previous items. */
val nextUp: LiveData<List<Song>>
@ -336,7 +336,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
}
override fun onPositionUpdate(position: Long) {
mPosition.value = position / 1000
mSeconds.value = position / 1000
}
override fun onQueueUpdate(queue: List<Song>, index: Int) {

View file

@ -162,6 +162,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
// / --- CONTROL METHODS ---
/**
* Show the panel, only if it's hidden.
* @return if the panel was shown
*/
fun show(): Boolean {
if (panelState == PanelState.HIDDEN) {
@ -172,6 +174,10 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
return false
}
/**
* Expand the panel if it is currently collapsed.
* @return If the panel was expanded
*/
fun expand(): Boolean {
if (panelState == PanelState.COLLAPSED) {
applyState(PanelState.EXPANDED)
@ -183,7 +189,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
/**
* Collapse the panel if it is currently expanded.
* @return If the panel was collapsed or not.
* @return If the panel was collapsed
*/
fun collapse(): Boolean {
if (panelState == PanelState.EXPANDED) {
@ -195,6 +201,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
}
/**
* Hide the panel if it is not hidden.
* @return If the panel was hidden
*/
fun hide(): Boolean {
if (panelState != PanelState.HIDDEN) {

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
/** A fragment enabling ViewBinding inflation and usage across the fragment lifecycle. */
abstract class ViewBindingFragment<T : ViewBinding> : Fragment() {
private var mBinding: T? = null
abstract fun onCreateBinding(inflater: LayoutInflater): T
abstract fun onBindingCreated(binding: T, savedInstanceState: Bundle?)
abstract fun onDestroyBinding(binding: T)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = onCreateBinding(inflater).also { mBinding = it }
onBindingCreated(binding, savedInstanceState)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
onDestroyBinding(requireBinding())
mBinding = null
}
protected val binding: T?
get() = mBinding
protected fun requireBinding(): T {
return requireNotNull(mBinding) {
"ViewBinding was not available, as the fragment is not in a valid state"
}
}
}

View file

@ -4,22 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
<variable
name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
@ -31,16 +15,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/menu_playback"
tools:subtitle="@string/lbl_all_songs"
app:title="@string/lbl_playback" />
app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginTop="@dimen/spacing_mid_large"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
@ -53,8 +35,8 @@
android:id="@+id/playback_song_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -67,8 +49,6 @@
style="@style/Widget.Auxio.TextView.Primary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song)}"
android:text="@{song.resolvedName}"
tools:text="Song Name" />
</FrameLayout>
@ -78,10 +58,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.resolvedArtistName}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -94,10 +72,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.resolvedAlbumName}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -105,19 +81,45 @@
app:layout_constraintTop_toBottomOf="@+id/playback_artist"
tools:text="Album Name" />
<org.oxycblt.auxio.playback.PlaybackSeekBar
<com.google.android.material.slider.Slider
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="-16dp"
android:layout_marginEnd="-16dp"
android:valueFrom="0"
android:valueTo="1"
app:haloRadius="@dimen/slider_halo_radius"
app:labelBehavior="gone"
android:layout_marginBottom="@dimen/spacing_medium"
app:labelStyle="@style/TextAppearance.Auxio.BodySmall"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_cover"
app:layout_constraintVertical_chainStyle="packed" />
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:thumbRadius="@dimen/slider_thumb_radius" />
<TextView
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="@color/sel_accented_secondary"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="11:38" />
<TextView
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small_inv"
android:layout_marginEnd="@dimen/spacing_medium"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton
android:id="@+id/playback_loop"
@ -125,7 +127,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:contentDescription="@string/desc_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
@ -150,13 +151,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_play_pause"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:src="@drawable/sel_playing_state"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
android:layout_marginBottom="@dimen/spacing_mid_large"
android:layout_marginBottom="@dimen/spacing_medium"
tools:src="@drawable/ic_play" />
<org.oxycblt.auxio.playback.PlaybackButton
@ -164,7 +163,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
@ -175,9 +173,8 @@
android:id="@+id/playback_shuffle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_shuffle"
android:layout_marginEnd="@dimen/spacing_medium"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"

View file

@ -38,8 +38,6 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/playback_song_container"
app:layout_constraintHorizontal_bias="0.5"
@ -66,8 +64,6 @@
style="@style/Widget.Auxio.TextView.Primary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song)}"
android:text="@{song.resolvedName}"
tools:text="Song Name" />
</FrameLayout>
@ -77,8 +73,6 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.resolvedArtistName}"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
@ -91,8 +85,6 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.resolvedAlbumName}"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
@ -100,17 +92,48 @@
app:layout_constraintTop_toBottomOf="@+id/playback_artist"
tools:text="Album Name" />
<org.oxycblt.auxio.playback.PlaybackSeekBar
<com.google.android.material.slider.Slider
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="-16dp"
android:layout_marginEnd="-16dp"
android:layout_marginBottom="@dimen/spacing_medium"
android:valueFrom="0"
android:valueTo="1"
app:haloRadius="@dimen/slider_halo_radius"
app:labelBehavior="gone"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
app:labelStyle="@style/TextAppearance.Auxio.BodySmall"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
app:layout_constraintTop_toBottomOf="@+id/playback_album" />
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_album"
app:thumbRadius="@dimen/slider_thumb_radius" />
<TextView
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="@color/sel_accented_secondary"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="11:38" />
<TextView
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton
android:id="@+id/playback_loop"
@ -118,7 +141,6 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_large"
android:contentDescription="@string/desc_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
@ -132,7 +154,6 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_prev"
android:onClick="@{() -> playbackModel.skipPrev()}"
android:src="@drawable/ic_skip_prev"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
@ -144,7 +165,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_play_pause"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:src="@drawable/sel_playing_state"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
@ -158,7 +178,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
@ -171,7 +190,6 @@
android:layout_marginStart="@dimen/spacing_large"
app:hasIndicator="true"
android:contentDescription="@string/desc_shuffle"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next"

View file

@ -4,22 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
<variable
name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
@ -38,8 +22,6 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_large"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_song"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -53,8 +35,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song)}"
android:text="@{song.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -68,8 +48,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.resolvedArtistName}"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -82,22 +60,52 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.resolvedAlbumName}"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Album Name" />
<org.oxycblt.auxio.playback.PlaybackSeekBar
<com.google.android.material.slider.Slider
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:valueFrom="0"
android:valueTo="1"
app:haloRadius="@dimen/slider_halo_radius"
app:labelBehavior="gone"
app:labelStyle="@style/TextAppearance.Auxio.BodySmall"
android:layout_marginBottom="@dimen/spacing_medium"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:thumbRadius="@dimen/slider_thumb_radius" />
<TextView
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="@color/sel_accented_secondary"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="11:38" />
<TextView
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton
android:id="@+id/playback_loop"
@ -105,7 +113,6 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_large"
android:contentDescription="@string/desc_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
@ -119,7 +126,6 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_prev"
android:onClick="@{() -> playbackModel.skipPrev()}"
android:src="@drawable/ic_skip_prev"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
@ -132,7 +138,6 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_large"
android:contentDescription="@string/desc_play_pause"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:src="@drawable/sel_playing_state"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
@ -145,7 +150,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
@ -157,7 +161,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:contentDescription="@string/desc_shuffle"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"

View file

@ -4,14 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<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"
@ -21,8 +13,6 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Medium"
android:layout_margin="@dimen/spacing_small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -35,7 +25,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:text="@{song.resolvedName}"
android:layout_marginEnd="@dimen/spacing_small"
app:layout_constraintBottom_toTopOf="@+id/playback_info"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
@ -52,7 +41,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:ellipsize="end"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toEndOf="@+id/playback_song"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
@ -101,7 +89,6 @@
android:id="@+id/playback_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="@{(int) song.seconds}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View file

@ -37,7 +37,7 @@
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"
android:layout_margin="@dimen/spacing_medium"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
@ -51,8 +51,8 @@
android:id="@+id/playback_song_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -76,8 +76,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.resolvedArtistName}"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
@ -92,8 +92,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.resolvedAlbumName}"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
@ -103,17 +103,46 @@
app:layout_constraintTop_toBottomOf="@+id/playback_artist"
tools:text="Album Name" />
<org.oxycblt.auxio.playback.PlaybackSeekBar
<com.google.android.material.slider.Slider
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:layout_marginBottom="@dimen/spacing_medium"
android:valueFrom="0"
android:valueTo="1"
app:haloRadius="@dimen/slider_halo_radius"
app:labelBehavior="gone"
app:labelStyle="@style/TextAppearance.Auxio.BodySmall"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_album" />
app:layout_constraintTop_toBottomOf="@+id/playback_album"
app:thumbRadius="@dimen/slider_thumb_radius" />
<TextView
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="@color/sel_accented_secondary"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="11:38" />
<TextView
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton
android:id="@+id/playback_loop"

View file

@ -4,14 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<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"
@ -21,8 +13,6 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -34,7 +24,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:text="@{song.resolvedName}"
android:layout_marginEnd="@dimen/spacing_small"
app:layout_constraintBottom_toTopOf="@+id/playback_info"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
@ -50,7 +39,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:ellipsize="end"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toEndOf="@+id/playback_song"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
@ -99,7 +87,7 @@
android:id="@+id/playback_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="@{(int) song.seconds}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View file

@ -4,14 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<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"
@ -21,8 +13,6 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -35,7 +25,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@{song.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/playback_info"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
@ -51,7 +40,6 @@
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:ellipsize="end"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
@ -73,7 +61,6 @@
android:id="@+id/playback_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="@{(int) song.seconds}"
app:trackColor="?attr/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View file

@ -4,21 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
<variable
name="playbackModel"
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
<variable
name="detailModel"
type="org.oxycblt.auxio.detail.DetailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
@ -36,11 +21,9 @@
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_song"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="@dimen/spacing_medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
tools:src="@drawable/ic_album" />
@ -50,10 +33,8 @@
style="@style/Widget.Auxio.TextView.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song)}"
android:text="@{song.resolvedName}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -65,10 +46,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.resolvedArtistName}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -79,24 +58,52 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.resolvedAlbumName}"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Album Name" />
<org.oxycblt.auxio.playback.PlaybackSeekBar
<com.google.android.material.slider.Slider
android:id="@+id/playback_seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:valueFrom="0"
android:valueTo="1"
app:haloRadius="@dimen/slider_halo_radius"
app:labelBehavior="gone"
app:labelStyle="@style/TextAppearance.Auxio.BodySmall"
android:layout_marginBottom="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:thumbRadius="@dimen/slider_thumb_radius" />
<TextView
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="@color/sel_accented_secondary"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="11:38" />
<TextView
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_small_inv"
android:textAppearance="@style/TextAppearance.Auxio.BodyMedium"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton
android:id="@+id/playback_loop"
@ -104,7 +111,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:contentDescription="@string/desc_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
@ -116,7 +122,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_prev"
android:onClick="@{() -> playbackModel.skipPrev()}"
android:src="@drawable/ic_skip_prev"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
@ -128,9 +133,8 @@
style="@style/Widget.Auxio.FloatingActionButton.PlayPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_mid_large"
android:layout_marginBottom="@dimen/spacing_medium"
android:contentDescription="@string/desc_play_pause"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:src="@drawable/sel_playing_state"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
@ -144,7 +148,6 @@
android:minHeight="@dimen/size_btn_small"
android:minWidth="@dimen/size_btn_small"
android:contentDescription="@string/desc_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
@ -159,7 +162,6 @@
android:minWidth="@dimen/size_btn_small"
android:layout_marginEnd="@dimen/spacing_medium"
android:contentDescription="@string/desc_shuffle"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"

View file

@ -26,7 +26,7 @@
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/playback_duration_current"
android:id="@+id/playback_seconds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
@ -38,7 +38,7 @@
tools:text="11:38" />
<TextView
android:id="@+id/playback_song_duration"
android:id="@+id/playback_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"

View file

@ -6,6 +6,8 @@
<dimen name="spacing_mid_large">24dp</dimen>
<dimen name="spacing_large">32dp</dimen>
<dimen name="spacing_small_inv">-8dp</dimen>
<!-- Size Namespace | Width & Heights for UI elements -->
<dimen name="size_btn_small">48dp</dimen>
<dimen name="size_btn_large">64dp</dimen>