Minor fixes

Do some more landscape layout fixes and remove some redundant database code.
This commit is contained in:
OxygenCobalt 2020-12-14 14:48:43 -07:00
parent 07e7e1ae5b
commit 8085c25103
20 changed files with 76 additions and 81 deletions

View file

@ -12,9 +12,9 @@ import androidx.databinding.DataBindingUtil
import org.oxycblt.auxio.databinding.ActivityMainBinding
import org.oxycblt.auxio.playback.PlaybackService
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.handleTransparentSystemBars
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.handleTransparentSystemBars
import org.oxycblt.auxio.ui.toColor
// FIXME: Fix bug where fast navigation will break the animations and
// lead to nothing being displayed [Possibly Un-fixable]

View file

@ -19,10 +19,10 @@ import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.getTransparentAccent
import org.oxycblt.auxio.utils.isLandscape
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.getTransparentAccent
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.toColor
import kotlin.IllegalArgumentException
class MainFragment : Fragment() {

View file

@ -8,7 +8,6 @@ package org.oxycblt.auxio.database
* @property index - The current index in the queue.
* @property mode - The integer form of the current [org.oxycblt.auxio.playback.state.PlaybackMode]
* @property isShuffling - A bool for if the queue was shuffled
* @property shuffleSeed - A long for the seed used to shuffle the queue [Used for quick-restore]
* @property loopMode - The integer form of the current [org.oxycblt.auxio.playback.state.LoopMode]
* @property inUserQueue - A bool for if the state was currently playing from the user queue.
* @author OxygenCobalt
@ -21,7 +20,6 @@ data class PlaybackState(
val index: Int,
val mode: Int,
val isShuffling: Boolean,
val shuffleSeed: Long,
val loopMode: Int,
val inUserQueue: Boolean
) {
@ -33,7 +31,6 @@ data class PlaybackState(
const val COLUMN_INDEX = "state_index"
const val COLUMN_MODE = "mode"
const val COLUMN_IS_SHUFFLING = "is_shuffling"
const val COLUMN_SHUFFLE_SEED = "shuffle_seed"
const val COLUMN_LOOP_MODE = "loop_mode"
const val COLUMN_IN_USER_QUEUE = "is_user_queue"
}

View file

@ -51,7 +51,6 @@ class PlaybackStateDatabase(context: Context) :
command.append("${PlaybackState.COLUMN_INDEX} INTEGER NOT NULL,")
command.append("${PlaybackState.COLUMN_MODE} INTEGER NOT NULL,")
command.append("${PlaybackState.COLUMN_IS_SHUFFLING} BOOLEAN NOT NULL,")
command.append("${PlaybackState.COLUMN_SHUFFLE_SEED} LONG NOT NULL,")
command.append("${PlaybackState.COLUMN_LOOP_MODE} INTEGER NOT NULL,")
command.append("${PlaybackState.COLUMN_IN_USER_QUEUE} BOOLEAN NOT NULL)")
@ -88,7 +87,7 @@ class PlaybackStateDatabase(context: Context) :
try {
database.beginTransaction()
val stateData = ContentValues(10)
val stateData = ContentValues(9)
stateData.put(PlaybackState.COLUMN_ID, state.id)
stateData.put(PlaybackState.COLUMN_SONG_ID, state.songId)
@ -97,7 +96,6 @@ class PlaybackStateDatabase(context: Context) :
stateData.put(PlaybackState.COLUMN_INDEX, state.index)
stateData.put(PlaybackState.COLUMN_MODE, state.mode)
stateData.put(PlaybackState.COLUMN_IS_SHUFFLING, state.isShuffling)
stateData.put(PlaybackState.COLUMN_SHUFFLE_SEED, state.shuffleSeed)
stateData.put(PlaybackState.COLUMN_LOOP_MODE, state.loopMode)
stateData.put(PlaybackState.COLUMN_IN_USER_QUEUE, state.inUserQueue)
@ -139,8 +137,6 @@ class PlaybackStateDatabase(context: Context) :
val modeIndex = cursor.getColumnIndexOrThrow(PlaybackState.COLUMN_MODE)
val isShufflingIndex =
cursor.getColumnIndexOrThrow(PlaybackState.COLUMN_IS_SHUFFLING)
val shuffleSeedIndex =
cursor.getColumnIndexOrThrow(PlaybackState.COLUMN_SHUFFLE_SEED)
val loopModeIndex = cursor.getColumnIndexOrThrow(PlaybackState.COLUMN_LOOP_MODE)
val inUserQueueIndex =
cursor.getColumnIndexOrThrow(PlaybackState.COLUMN_IN_USER_QUEUE)
@ -155,7 +151,6 @@ class PlaybackStateDatabase(context: Context) :
index = cursor.getInt(indexIndex),
mode = cursor.getInt(modeIndex),
isShuffling = cursor.getInt(isShufflingIndex) == 1,
shuffleSeed = cursor.getLong(shuffleSeedIndex),
loopMode = cursor.getInt(loopModeIndex),
inUserQueue = cursor.getInt(inUserQueueIndex) == 1
)

View file

@ -17,9 +17,9 @@ import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.utils.createToast
import org.oxycblt.auxio.utils.disable
import org.oxycblt.auxio.utils.setupAlbumSongActions
import org.oxycblt.auxio.ui.createToast
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setupAlbumSongActions
/**
* The [DetailFragment] for an album.

View file

@ -15,8 +15,8 @@ import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.utils.disable
import org.oxycblt.auxio.utils.setupAlbumActions
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setupAlbumActions
/**
* The [DetailFragment] for an artist.

View file

@ -14,8 +14,8 @@ import org.oxycblt.auxio.detail.adapters.GenreArtistAdapter
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.utils.disable
import org.oxycblt.auxio.utils.setupArtistActions
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setupArtistActions
/**
* The [DetailFragment] for a genre.

View file

@ -9,8 +9,8 @@ import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.toColor
/**
* An adapter for displaying the [Song]s of an album.

View file

@ -28,13 +28,13 @@ import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.utils.applyColor
import org.oxycblt.auxio.utils.isLandscape
import org.oxycblt.auxio.utils.resolveAttr
import org.oxycblt.auxio.utils.setupAlbumActions
import org.oxycblt.auxio.utils.setupArtistActions
import org.oxycblt.auxio.utils.setupGenreActions
import org.oxycblt.auxio.utils.setupSongActions
import org.oxycblt.auxio.ui.applyColor
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.resolveAttr
import org.oxycblt.auxio.ui.setupAlbumActions
import org.oxycblt.auxio.ui.setupArtistActions
import org.oxycblt.auxio.ui.setupGenreActions
import org.oxycblt.auxio.ui.setupSongActions
/**
* A [Fragment] that shows a custom list of [Genre], [Artist], or [Album] data. Also allows for

View file

@ -16,8 +16,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.toColor
/**
* A [Fragment] that displays more information about the song, along with more media controls.

View file

@ -564,7 +564,6 @@ class PlaybackStateManager private constructor() {
index = mIndex,
mode = intMode,
isShuffling = mIsShuffling,
shuffleSeed = mShuffleSeed,
loopMode = intLoopMode,
inUserQueue = mIsInUserQueue
)
@ -598,7 +597,6 @@ class PlaybackStateManager private constructor() {
mMode = PlaybackMode.fromInt(playbackState.mode) ?: PlaybackMode.ALL_SONGS
mLoopMode = LoopMode.fromInt(playbackState.loopMode) ?: LoopMode.NONE
mIsShuffling = playbackState.isShuffling
mShuffleSeed = playbackState.shuffleSeed
mIsInUserQueue = playbackState.inUserQueue
mIndex = playbackState.index

View file

@ -22,8 +22,8 @@ import androidx.dynamicanimation.animation.SpringForce
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
import com.reddit.indicatorfastscroll.FastScrollerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.toColor
/**
* A semi-copy, semi-custom implementation of [com.reddit.indicatorfastscroll.FastScrollerThumbView]

View file

@ -18,10 +18,10 @@ import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.settings.adapters.AccentAdapter
import org.oxycblt.auxio.utils.ACCENTS
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.createToast
import org.oxycblt.auxio.utils.getDetailedAccentSummary
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.createToast
import org.oxycblt.auxio.ui.getDetailedAccentSummary
@Suppress("UNUSED")
class SettingsListFragment : PreferenceFragmentCompat() {

View file

@ -6,7 +6,7 @@ import androidx.preference.PreferenceManager
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.utils.ACCENTS
import org.oxycblt.auxio.ui.ACCENTS
/**
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.

View file

@ -6,10 +6,10 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ItemAccentBinding
import org.oxycblt.auxio.utils.ACCENTS
import org.oxycblt.auxio.utils.accent
import org.oxycblt.auxio.utils.getAccentItemSummary
import org.oxycblt.auxio.utils.toColor
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.getAccentItemSummary
import org.oxycblt.auxio.ui.toColor
class AccentAdapter(
private val doOnAccentConfirm: (accent: Pair<Int, Int>) -> Unit

View file

@ -18,8 +18,8 @@ import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.utils.isLandscape
import org.oxycblt.auxio.utils.setupSongActions
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.setupSongActions
import kotlin.math.ceil
/**

View file

@ -1,4 +1,4 @@
package org.oxycblt.auxio.utils
package org.oxycblt.auxio.ui
import android.annotation.TargetApi
import android.content.Context

View file

@ -1,4 +1,4 @@
package org.oxycblt.auxio.utils
package org.oxycblt.auxio.ui
import android.content.Context
import android.content.res.Resources

View file

@ -63,7 +63,7 @@
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toTopOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
@ -81,7 +81,6 @@
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_song"
tools:text="Artist Name" />
@ -92,7 +91,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginEnd="@dimen/margin_mid_large"
android:layout_marginBottom="16dp"
android:ellipsize="end"
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song.album)}"
android:singleLine="true"
@ -101,7 +99,6 @@
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_artist"
tools:text="Album Name" />
@ -110,6 +107,7 @@
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:clickable="true"
android:focusable="true"
android:paddingStart="@dimen/margin_mid_large"
@ -121,7 +119,6 @@
android:thumbTint="?attr/colorPrimary"
app:layout_constraintBottom_toTopOf="@+id/playback_duration_current"
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"
tools:progress="70" />
@ -131,7 +128,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginBottom="@dimen/margin_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
@ -142,26 +138,27 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_mid_large"
android:layout_marginBottom="@dimen/margin_medium"
android:text="@{song.formattedDuration}"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" />
<ImageButton
android:id="@+id/playback_play_pause"
android:layout_width="@dimen/size_play_pause"
android:layout_height="@dimen/size_play_pause"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginEnd="@dimen/margin_large"
android:background="@drawable/ui_circular_button"
android:backgroundTint="?attr/colorPrimary"
android:contentDescription="@{playbackModel.isPlaying ? @string/description_pause : @string/description_play}"
android:foregroundTint="@color/background"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:tint="@color/background"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_next"
app:layout_constraintStart_toEndOf="@+id/playback_skip_prev"
app:layout_constraintTop_toBottomOf="@+id/playback_duration_current"
tools:src="@drawable/ic_play_to_pause" />
@ -170,12 +167,13 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginEnd="@dimen/margin_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
@ -184,13 +182,14 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginEnd="@dimen/margin_mid_large"
android:layout_marginStart="@dimen/margin_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_skip_prev"
android:onClick="@{() -> playbackModel.skipPrev()}"
android:src="@drawable/ic_skip_prev_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_loop"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<ImageButton
@ -198,28 +197,29 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginStart="@dimen/margin_mid_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@{playbackModel.isShuffling() ? @string/description_shuffle_off : @string/description_shuffle_on"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="@+id/playback_song_duration"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
app:layout_constraintTop_toTopOf="@+id/playback_skip_next" />
<ImageButton
android:id="@+id/playback_loop"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginEnd="@dimen/margin_mid_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="@+id/playback_duration_current"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -148,6 +148,8 @@
android:id="@+id/playback_play_pause"
android:layout_width="@dimen/size_play_pause"
android:layout_height="@dimen/size_play_pause"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
android:layout_marginBottom="@dimen/margin_medium"
android:background="@drawable/ui_circular_button"
android:backgroundTint="?attr/colorPrimary"
@ -156,8 +158,8 @@
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:tint="@color/background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_next"
app:layout_constraintStart_toEndOf="@+id/playback_skip_prev"
tools:src="@drawable/ic_play_to_pause" />
<ImageButton
@ -165,12 +167,13 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginStart="@dimen/margin_mid_large"
android:layout_marginEnd="@dimen/margin_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_skip_next"
android:onClick="@{() -> playbackModel.skipNext()}"
android:src="@drawable/ic_skip_next_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
@ -179,13 +182,14 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginEnd="@dimen/margin_mid_large"
android:layout_marginStart="@dimen/margin_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_skip_prev"
android:onClick="@{() -> playbackModel.skipPrev()}"
android:src="@drawable/ic_skip_prev_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_loop"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<ImageButton
@ -193,28 +197,29 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginStart="@dimen/margin_mid_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@{playbackModel.isShuffling() ? @string/description_shuffle_off : @string/description_shuffle_on"
android:onClick="@{() -> playbackModel.invertShuffleStatus()}"
android:src="@drawable/ic_shuffle_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
app:layout_constraintTop_toTopOf="@+id/playback_skip_next" />
<ImageButton
android:id="@+id/playback_loop"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/size_play_pause_compact"
android:layout_height="@dimen/size_play_pause_compact"
android:layout_marginEnd="@dimen/margin_mid_large"
android:background="@drawable/ui_unbounded_ripple"
android:contentDescription="@string/description_change_loop"
android:onClick="@{() -> playbackModel.incrementLoopStatus()}"
android:src="@drawable/ic_loop_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>