all: remove databinding

Remove databinding entirely.

Databinding was a terrible idea for Auxio. I rarely leveraged it, and
when I did, it produced messy code and bloated build times. Dumpster it
for just viewbinding, which is good. This reduces building times by
nearly 2/3, and generally makes the codebase more coherent and usable.
This commit is contained in:
OxygenCobalt 2022-03-23 10:53:47 -06:00
parent 95057ec357
commit d79592e029
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
61 changed files with 861 additions and 1307 deletions

View file

@ -17,7 +17,7 @@ android {
targetSdkVersion 32
buildFeatures {
dataBinding true
viewBinding true
}
}

View file

@ -26,8 +26,6 @@ import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.updatePadding
import androidx.databinding.DataBindingUtil
import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.databinding.ActivityMainBinding
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.system.PlaybackService
@ -54,10 +52,9 @@ class MainActivity : AppCompatActivity() {
setupTheme()
val binding =
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
applyEdgeToEdgeWindow(binding)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
applyEdgeToEdgeWindow(binding.root)
logD("Activity created")
}
@ -114,7 +111,7 @@ class MainActivity : AppCompatActivity() {
}
}
private fun applyEdgeToEdgeWindow(binding: ViewBinding) {
private fun applyEdgeToEdgeWindow(contentView: View) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
logD("Doing R+ edge-to-edge")
@ -124,7 +121,7 @@ class MainActivity : AppCompatActivity() {
// the R+ SDK decides to make you specify the insets yourself with a barely
// documented API that isn't even mentioned in any of the edge-to-edge
// tutorials. Thanks android, very cool!
binding.root.setOnApplyWindowInsetsListener { _, insets ->
contentView.setOnApplyWindowInsetsListener { view, insets ->
WindowInsets.Builder()
.setInsets(
WindowInsets.Type.systemBars(),
@ -133,27 +130,25 @@ class MainActivity : AppCompatActivity() {
WindowInsets.Type.systemGestures(),
insets.getInsetsIgnoringVisibility(WindowInsets.Type.systemGestures()))
.build()
.applyLeftRightInsets(binding)
.applyLeftRightInsets(view)
}
} else {
// Do old edge-to-edge otherwise.
logD("Doing legacy edge-to-edge")
@Suppress("DEPRECATION")
binding.root.apply {
contentView.apply {
systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
setOnApplyWindowInsetsListener { _, insets -> insets.applyLeftRightInsets(binding) }
setOnApplyWindowInsetsListener { view, insets -> insets.applyLeftRightInsets(view) }
}
}
}
private fun WindowInsets.applyLeftRightInsets(binding: ViewBinding): WindowInsets {
private fun WindowInsets.applyLeftRightInsets(contentView: View): WindowInsets {
val bars = systemBarInsetsCompat
binding.root.updatePadding(left = bars.left, right = bars.right)
contentView.updatePadding(left = bars.left, right = bars.right)
return replaceSystemBarInsetsCompat(0, bars.top, 0, bars.bottom)
}

View file

@ -23,7 +23,6 @@ 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
import coil.imageLoader
import coil.load
@ -39,28 +38,25 @@ import org.oxycblt.auxio.music.Song
// --- BINDING ADAPTERS ---
/** Bind the album cover for a [song]. */
@BindingAdapter("albumArt")
fun ImageView.bindAlbumCover(song: Song?) =
fun ImageView.applyAlbumCover(song: Song?) =
load(song, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the album cover for an [album]. */
@BindingAdapter("albumArt")
fun ImageView.bindAlbumCover(album: Album?) =
fun ImageView.applyAlbumCover(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?) =
fun ImageView.applyArtistImage(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?) =
fun ImageView.applyGenreImage(genre: Genre?) =
load(genre, R.drawable.ic_genre, R.string.desc_genre_image)
fun <T : Music> ImageView.load(music: T?, @DrawableRes error: Int, @StringRes desc: Int) {
contentDescription = context.getString(desc, music?.resolvedName)
dispose()
scaleType = ImageView.ScaleType.FIT_CENTER
load(music) {
error(error)
transformations(SquareFrameTransform.INSTANCE)

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.bindAlbumCover
import org.oxycblt.auxio.coil.applyAlbumCover
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.detail.DetailViewModel
@ -32,12 +32,14 @@ import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Item
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.toDuration
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ActionHeaderViewHolder
import org.oxycblt.auxio.ui.BaseViewHolder
import org.oxycblt.auxio.ui.DiffCallback
import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe
/**
* An adapter for displaying the details and [Song]s of an [Album]
@ -127,14 +129,14 @@ class AlbumDetailAdapter(
override fun onBind(data: Album) {
binding.detailCover.apply {
bindAlbumCover(data)
applyAlbumCover(data)
contentDescription = context.getString(R.string.desc_album_cover, data.resolvedName)
}
binding.detailName.text = data.resolvedName
binding.detailName.textSafe = data.resolvedName
binding.detailSubhead.apply {
text = data.artist.resolvedName
textSafe = data.artist.resolvedName
setOnClickListener { detailModel.navToItem(data.artist) }
}
@ -157,14 +159,25 @@ class AlbumDetailAdapter(
private val binding: ItemAlbumSongBinding,
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick), Highlightable {
override fun onBind(data: Song) {
binding.song = data
binding.songName.requestLayout()
// Hide the track number view if the song does not have a track.
if (data.track != null) {
binding.songTrack.apply {
textSafe = context.getString(R.string.fmt_number, data.track)
isInvisible = false
}
// Hide the track number view if the track is zero, as generally a track number of
// zero implies that the song does not have a track number.
val usePlaceholder = data.track == null
binding.songTrack.isInvisible = usePlaceholder
binding.songTrackPlaceholder.isInvisible = !usePlaceholder
binding.songTrackPlaceholder.isInvisible = true
} else {
binding.songTrack.apply {
textSafe = ""
isInvisible = true
}
binding.songTrackPlaceholder.isInvisible = false
}
binding.songName.textSafe = data.resolvedName
binding.songDuration.textSafe = data.seconds.toDuration(false)
}
override fun setHighlighted(isHighlighted: Boolean) {

View file

@ -23,23 +23,26 @@ 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.bindArtistImage
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.databinding.ItemArtistSongBinding
import org.oxycblt.auxio.coil.applyAlbumCover
import org.oxycblt.auxio.coil.applyArtistImage
import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.databinding.ItemParentBinding
import org.oxycblt.auxio.databinding.ItemSongBinding
import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Item
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.bindArtistInfo
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ActionHeaderViewHolder
import org.oxycblt.auxio.ui.BaseViewHolder
import org.oxycblt.auxio.ui.DiffCallback
import org.oxycblt.auxio.ui.HeaderViewHolder
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe
/**
* An adapter for displaying the [Album]s and [Song]s of an artist.
@ -73,9 +76,9 @@ class ArtistDetailAdapter(
IntegerTable.ITEM_TYPE_ARTIST_DETAIL ->
ArtistDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
IntegerTable.ITEM_TYPE_ARTIST_ALBUM ->
ArtistAlbumViewHolder(ItemArtistAlbumBinding.inflate(parent.context.inflater))
ArtistAlbumViewHolder(ItemParentBinding.inflate(parent.context.inflater))
IntegerTable.ITEM_TYPE_ARTIST_SONG ->
ArtistSongViewHolder(ItemArtistSongBinding.inflate(parent.context.inflater))
ArtistSongViewHolder(ItemSongBinding.inflate(parent.context.inflater))
IntegerTable.ITEM_TYPE_HEADER -> HeaderViewHolder.from(parent.context)
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
else -> error("Invalid ViewHolder item type $viewType")
@ -173,16 +176,16 @@ class ArtistDetailAdapter(
val context = binding.root.context
binding.detailCover.apply {
bindArtistImage(data)
applyArtistImage(data)
contentDescription =
context.getString(R.string.desc_artist_image, data.resolvedName)
}
binding.detailName.text = data.resolvedName
binding.detailName.textSafe = data.resolvedName
// Get the genre that corresponds to the most songs in this artist, which would be
// the most "Prominent" genre.
binding.detailSubhead.text =
binding.detailSubhead.textSafe =
data.songs
.groupBy { it.genre.resolvedName }
.entries
@ -190,7 +193,11 @@ class ArtistDetailAdapter(
?.key
?: context.getString(R.string.def_genre)
binding.detailInfo.bindArtistInfo(data)
binding.detailInfo.textSafe =
binding.context.getString(
R.string.fmt_two,
binding.context.getPluralSafe(R.plurals.fmt_album_count, data.albums.size),
binding.context.getPluralSafe(R.plurals.fmt_song_count, data.songs.size))
binding.detailPlayButton.setOnClickListener { playbackModel.playArtist(data, false) }
@ -199,24 +206,26 @@ class ArtistDetailAdapter(
}
inner class ArtistAlbumViewHolder(
private val binding: ItemArtistAlbumBinding,
private val binding: ItemParentBinding,
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick), Highlightable {
override fun onBind(data: Album) {
binding.album = data
binding.albumName.requestLayout()
binding.parentImage.applyAlbumCover(data)
binding.parentName.textSafe = data.resolvedName
binding.parentInfo.textSafe = binding.context.getString(R.string.fmt_number, data.year)
}
override fun setHighlighted(isHighlighted: Boolean) {
binding.albumName.isActivated = isHighlighted
binding.parentName.isActivated = isHighlighted
}
}
inner class ArtistSongViewHolder(
private val binding: ItemArtistSongBinding,
private val binding: ItemSongBinding,
) : BaseViewHolder<Song>(binding, doOnSongClick, doOnLongClick), Highlightable {
override fun onBind(data: Song) {
binding.song = data
binding.songName.requestLayout()
binding.songAlbumCover.applyAlbumCover(data)
binding.songName.textSafe = data.resolvedName
binding.songInfo.textSafe = data.resolvedAlbumName
}
override fun setHighlighted(isHighlighted: Boolean) {

View file

@ -23,19 +23,22 @@ 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.bindGenreImage
import org.oxycblt.auxio.coil.applyAlbumCover
import org.oxycblt.auxio.coil.applyGenreImage
import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.databinding.ItemGenreSongBinding
import org.oxycblt.auxio.databinding.ItemSongBinding
import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Item
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.bindGenreInfo
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ActionHeaderViewHolder
import org.oxycblt.auxio.ui.BaseViewHolder
import org.oxycblt.auxio.ui.DiffCallback
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe
/**
* An adapter for displaying the [Song]s of a genre.
@ -64,9 +67,7 @@ class GenreDetailAdapter(
GenreDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
IntegerTable.ITEM_TYPE_GENRE_SONG ->
GenreSongViewHolder(
ItemGenreSongBinding.inflate(parent.context.inflater),
)
GenreSongViewHolder(ItemSongBinding.inflate(parent.context.inflater))
else -> error("Bad ViewHolder item type $viewType")
}
}
@ -127,13 +128,14 @@ class GenreDetailAdapter(
val context = binding.root.context
binding.detailCover.apply {
bindGenreImage(data)
applyGenreImage(data)
contentDescription = context.getString(R.string.desc_genre_image, data.resolvedName)
}
binding.detailName.text = data.resolvedName
binding.detailSubhead.bindGenreInfo(data)
binding.detailInfo.text = data.totalDuration
binding.detailName.textSafe = data.resolvedName
binding.detailSubhead.textSafe =
binding.context.getPluralSafe(R.plurals.fmt_song_count, data.songs.size)
binding.detailInfo.textSafe = data.totalDuration
binding.detailPlayButton.setOnClickListener { playbackModel.playGenre(data, false) }
@ -141,14 +143,16 @@ class GenreDetailAdapter(
}
}
inner class GenreSongViewHolder(
private val binding: ItemGenreSongBinding,
/** The Shared ViewHolder for a [Song]. Instantiation should be done with [from]. */
inner class GenreSongViewHolder
constructor(
private val binding: ItemSongBinding,
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick), Highlightable {
override fun onBind(data: Song) {
binding.song = data
binding.songName.requestLayout()
binding.songInfo.requestLayout()
override fun onBind(data: Song) {
binding.songAlbumCover.applyAlbumCover(data)
binding.songName.textSafe = data.resolvedName
binding.songInfo.textSafe = data.resolvedArtistName
}
override fun setHighlighted(isHighlighted: Boolean) {

View file

@ -186,6 +186,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
// --- RECYCLERVIEW EVENT MANAGEMENT ---
private fun onPreDraw() {
// FIXME: Make the way we lay out views less of a hacky mess. Perhaps consider
// overlaying views or turning this into a ViewGroup.
updateScrollbarState()
thumbView.layoutDirection = layoutDirection

View file

@ -18,12 +18,7 @@
package org.oxycblt.auxio.music
import android.text.format.DateUtils
import android.widget.TextView
import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW
// --- EXTENSION FUNCTIONS ---
@ -47,53 +42,3 @@ fun Long.toDuration(isElapsed: Boolean): String {
return durationString
}
// --- BINDING ADAPTERS ---
@BindingAdapter("songInfo")
fun TextView.bindSongInfo(song: Song?) {
if (song == null) {
logW("Song was null, not applying info")
return
}
text = context.getString(R.string.fmt_two, song.resolvedArtistName, song.resolvedAlbumName)
}
@BindingAdapter("albumInfo")
fun TextView.bindAlbumInfo(album: Album?) {
if (album == null) {
logW("Album was null, not applying info")
return
}
text =
context.getString(
R.string.fmt_two,
album.resolvedArtistName,
context.getPluralSafe(R.plurals.fmt_song_count, album.songs.size))
}
@BindingAdapter("artistInfo")
fun TextView.bindArtistInfo(artist: Artist?) {
if (artist == null) {
logW("Artist was null, not applying info")
return
}
text =
context.getString(
R.string.fmt_two,
context.getPluralSafe(R.plurals.fmt_album_count, artist.albums.size),
context.getPluralSafe(R.plurals.fmt_song_count, artist.songs.size))
}
@BindingAdapter("genreInfo")
fun TextView.bindGenreInfo(genre: Genre?) {
if (genre == null) {
logW("Genre was null, not applying info")
return
}
text = context.getPluralSafe(R.plurals.fmt_song_count, genre.songs.size)
}

View file

@ -22,6 +22,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemExcludedDirBinding
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe
/**
* Adapter that shows the excluded directories and their "Clear" button.
@ -56,8 +57,7 @@ class ExcludedEntryAdapter(private val onClear: (String) -> Unit) :
}
fun bind(path: String) {
binding.excludedPath.text = path
binding.excludedPath.requestLayout()
binding.excludedPath.textSafe = path
binding.excludedClear.setOnClickListener { onClear(path) }
}
}

View file

@ -25,14 +25,14 @@ import androidx.core.view.updatePadding
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.coil.applyAlbumCover
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.ui.ViewBindingFragment
import org.oxycblt.auxio.util.getAttrColorSafe
import org.oxycblt.auxio.util.systemBarInsetsCompat
import org.oxycblt.auxio.util.textSafe
class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
private val playbackModel: PlaybackViewModel by activityViewModels()
@ -99,9 +99,10 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (song != null) {
binding.playbackCover.bindAlbumCover(song)
binding.playbackSong.text = song.resolvedName
binding.playbackInfo.bindSongInfo(song)
binding.playbackCover.applyAlbumCover(song)
binding.playbackSong.textSafe = song.resolvedName
binding.playbackInfo.textSafe =
getString(R.string.fmt_two, song.resolvedArtistName, song.resolvedAlbumName)
binding.playbackProgressBar.max = song.seconds.toInt()
}
}

View file

@ -29,7 +29,7 @@ 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.coil.applyAlbumCover
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.MusicParent
@ -42,6 +42,7 @@ import org.oxycblt.auxio.util.getAttrColorSafe
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.stateList
import org.oxycblt.auxio.util.systemBarInsetsCompat
import org.oxycblt.auxio.util.textSafe
/**
* A [Fragment] that displays more information about the song, along with more media controls.
@ -166,7 +167,7 @@ class PlaybackPanelFragment :
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
if (fromUser) {
requireBinding().playbackPosition.text = value.toLong().toDuration(true)
requireBinding().playbackPosition.textSafe = value.toLong().toDuration(true)
}
}
@ -174,14 +175,14 @@ class PlaybackPanelFragment :
if (song == null) return
val binding = requireBinding()
binding.playbackCover.bindAlbumCover(song)
binding.playbackSong.text = song.resolvedName
binding.playbackArtist.text = song.resolvedArtistName
binding.playbackAlbum.text = song.resolvedAlbumName
binding.playbackCover.applyAlbumCover(song)
binding.playbackSong.textSafe = song.resolvedName
binding.playbackArtist.textSafe = song.resolvedArtistName
binding.playbackAlbum.textSafe = song.resolvedAlbumName
// Normally if a song had a duration
val seconds = song.seconds
binding.playbackDuration.text = seconds.toDuration(false)
binding.playbackDuration.textSafe = seconds.toDuration(false)
binding.playbackSeekBar.apply {
valueTo = max(seconds, 1L).toFloat()
isEnabled = seconds > 0L
@ -199,7 +200,7 @@ class PlaybackPanelFragment :
val binding = requireBinding()
if (!binding.playbackPosition.isActivated) {
binding.playbackSeekBar.value = position.toFloat()
binding.playbackPosition.text = position.toDuration(true)
binding.playbackPosition.textSafe = position.toDuration(true)
}
}

View file

@ -65,6 +65,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
private val mMode = MutableLiveData(PlaybackMode.ALL_SONGS)
// Other
// TODO: Move URI management to PlaybackService (more capable of taking commands)
private var mIntentUri: Uri? = null
/** The current song. */

View file

@ -28,6 +28,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.coil.applyAlbumCover
import org.oxycblt.auxio.databinding.ItemQueueSongBinding
import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Header
@ -41,6 +42,7 @@ import org.oxycblt.auxio.util.disableDropShadowCompat
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.stateList
import org.oxycblt.auxio.util.textSafe
/**
* The single adapter for both the Next Queue and the User Queue.
@ -125,7 +127,9 @@ class QueueAdapter(private val touchHelper: ItemTouchHelper) :
@SuppressLint("ClickableViewAccessibility")
override fun onBind(data: Song) {
binding.song = data
binding.songAlbumCover.applyAlbumCover(data)
binding.songName.textSafe = data.resolvedName
binding.songInfo.textSafe = data.resolvedArtistName
binding.background.isInvisible = true

View file

@ -36,6 +36,7 @@ import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.systemBarInsetsCompat
import org.oxycblt.auxio.util.textSafe
/**
* A [BottomSheetDialogFragment] that shows Auxio's about screen.
@ -54,13 +55,13 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
binding.aboutToolbar.setNavigationOnClickListener { findNavController().navigateUp() }
binding.aboutVersion.text = BuildConfig.VERSION_NAME
binding.aboutVersion.textSafe = BuildConfig.VERSION_NAME
binding.aboutCode.setOnClickListener { openLinkInBrowser(LINK_CODEBASE) }
binding.aboutFaq.setOnClickListener { openLinkInBrowser(LINK_FAQ) }
binding.aboutLicenses.setOnClickListener { openLinkInBrowser(LINK_LICENSES) }
homeModel.songs.observe(viewLifecycleOwner) { songs ->
binding.aboutSongCount.text = getString(R.string.fmt_songs_loaded, songs.size)
binding.aboutSongCount.textSafe = getString(R.string.fmt_songs_loaded, songs.size)
}
}

View file

@ -249,11 +249,11 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
barView = getChildAt(1) // Child 2 is assumed to be the bar used when collapsed
panelView = getChildAt(2) // Child 3 is assumed to be the panel used when expanded
// We actually move the bar and panel views into a container so that they have consistent
// behavior when be manipulate layouts later.
removeView(barView)
removeView(panelView)
// We actually move the bar and panel views into a container so that they have consistent
// behavior when be manipulate layouts later.
containerView.apply {
addView(
barView,

View file

@ -20,13 +20,15 @@ package org.oxycblt.auxio.ui
import android.content.Context
import android.view.View
import androidx.appcompat.widget.TooltipCompat
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.applyAlbumCover
import org.oxycblt.auxio.coil.applyArtistImage
import org.oxycblt.auxio.coil.applyGenreImage
import org.oxycblt.auxio.databinding.ItemActionHeaderBinding
import org.oxycblt.auxio.databinding.ItemAlbumBinding
import org.oxycblt.auxio.databinding.ItemArtistBinding
import org.oxycblt.auxio.databinding.ItemGenreBinding
import org.oxycblt.auxio.databinding.ItemHeaderBinding
import org.oxycblt.auxio.databinding.ItemParentBinding
import org.oxycblt.auxio.databinding.ItemSongBinding
import org.oxycblt.auxio.music.ActionHeader
import org.oxycblt.auxio.music.Album
@ -35,7 +37,10 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Item
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe
/**
* A [RecyclerView.ViewHolder] that streamlines a lot of the common things across all viewholders.
@ -46,7 +51,7 @@ import org.oxycblt.auxio.util.inflater
* @author OxygenCobalt
*/
abstract class BaseViewHolder<T : Item>(
private val binding: ViewDataBinding,
private val binding: ViewBinding,
private val doOnClick: ((data: T) -> Unit)? = null,
private val doOnLongClick: ((view: View, data: T) -> Unit)? = null
) : RecyclerView.ViewHolder(binding.root) {
@ -73,8 +78,6 @@ abstract class BaseViewHolder<T : Item>(
}
onBind(data)
binding.executePendingBindings()
}
/**
@ -93,10 +96,9 @@ private constructor(
) : BaseViewHolder<Song>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Song) {
binding.song = data
binding.songName.requestLayout()
binding.songInfo.requestLayout()
binding.songAlbumCover.applyAlbumCover(data)
binding.songName.textSafe = data.resolvedName
binding.songInfo.textSafe = data.resolvedArtistName
}
companion object {
@ -115,14 +117,19 @@ private constructor(
/** The Shared ViewHolder for a [Album]. Instantiation should be done with [from]. */
class AlbumViewHolder
private constructor(
private val binding: ItemAlbumBinding,
private val binding: ItemParentBinding,
doOnClick: (data: Album) -> Unit,
doOnLongClick: (view: View, data: Album) -> Unit
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Album) {
binding.album = data
binding.albumName.requestLayout()
binding.parentImage.applyAlbumCover(data)
binding.parentName.textSafe = data.resolvedName
binding.parentInfo.textSafe =
binding.context.getString(
R.string.fmt_two,
data.resolvedArtistName,
binding.context.getPluralSafe(R.plurals.fmt_song_count, data.songs.size))
}
companion object {
@ -133,7 +140,7 @@ private constructor(
doOnLongClick: (view: View, data: Album) -> Unit
): AlbumViewHolder {
return AlbumViewHolder(
ItemAlbumBinding.inflate(context.inflater), doOnClick, doOnLongClick)
ItemParentBinding.inflate(context.inflater), doOnClick, doOnLongClick)
}
}
}
@ -141,14 +148,19 @@ private constructor(
/** The Shared ViewHolder for a [Artist]. Instantiation should be done with [from]. */
class ArtistViewHolder
private constructor(
private val binding: ItemArtistBinding,
private val binding: ItemParentBinding,
doOnClick: (Artist) -> Unit,
doOnLongClick: (view: View, data: Artist) -> Unit
) : BaseViewHolder<Artist>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Artist) {
binding.artist = data
binding.artistName.requestLayout()
binding.parentImage.applyArtistImage(data)
binding.parentName.textSafe = data.resolvedName
binding.parentInfo.textSafe =
binding.context.getString(
R.string.fmt_two,
binding.context.getPluralSafe(R.plurals.fmt_album_count, data.albums.size),
binding.context.getPluralSafe(R.plurals.fmt_song_count, data.songs.size))
}
companion object {
@ -159,7 +171,7 @@ private constructor(
doOnLongClick: (view: View, data: Artist) -> Unit
): ArtistViewHolder {
return ArtistViewHolder(
ItemArtistBinding.inflate(context.inflater), doOnClick, doOnLongClick)
ItemParentBinding.inflate(context.inflater), doOnClick, doOnLongClick)
}
}
}
@ -167,14 +179,16 @@ private constructor(
/** The Shared ViewHolder for a [Genre]. Instantiation should be done with [from]. */
class GenreViewHolder
private constructor(
private val binding: ItemGenreBinding,
private val binding: ItemParentBinding,
doOnClick: (Genre) -> Unit,
doOnLongClick: (view: View, data: Genre) -> Unit
) : BaseViewHolder<Genre>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Genre) {
binding.genre = data
binding.genreName.requestLayout()
binding.parentImage.applyGenreImage(data)
binding.parentName.textSafe = data.resolvedName
binding.parentInfo.textSafe =
binding.context.getPluralSafe(R.plurals.fmt_song_count, data.songs.size)
}
companion object {
@ -185,7 +199,7 @@ private constructor(
doOnLongClick: (view: View, data: Genre) -> Unit
): GenreViewHolder {
return GenreViewHolder(
ItemGenreBinding.inflate(context.inflater), doOnClick, doOnLongClick)
ItemParentBinding.inflate(context.inflater), doOnClick, doOnLongClick)
}
}
}
@ -195,7 +209,7 @@ class HeaderViewHolder private constructor(private val binding: ItemHeaderBindin
BaseViewHolder<Header>(binding) {
override fun onBind(data: Header) {
binding.header = data
binding.title.textSafe = binding.context.getString(data.string)
}
companion object {
@ -211,13 +225,11 @@ class ActionHeaderViewHolder private constructor(private val binding: ItemAction
BaseViewHolder<ActionHeader>(binding) {
override fun onBind(data: ActionHeader) {
binding.header = data
binding.executePendingBindings()
binding.headerTitle.textSafe = binding.context.getString(data.string)
binding.headerButton.apply {
setImageResource(data.icon)
contentDescription = context.getString(data.desc)
TooltipCompat.setTooltipText(this, contentDescription)
setOnClickListener(data.onClick)
}
}

View file

@ -17,6 +17,7 @@
package org.oxycblt.auxio.util
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Insets
import android.graphics.Rect
@ -24,44 +25,14 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import android.view.WindowInsets
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.core.graphics.drawable.DrawableCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.R
/** Converts this color to a single-color [ColorStateList]. */
val @receiver:ColorRes Int.stateList
get() = ColorStateList.valueOf(this)
/**
* Apply the recommended spans for a [RecyclerView].
*
* @param shouldBeFullWidth Optional callback for determining whether an item should be full-width,
* regardless of spans
*/
fun RecyclerView.applySpans(shouldBeFullWidth: ((Int) -> Boolean)? = null) {
val spans = resources.getInteger(R.integer.recycler_spans)
if (spans > 1) {
val mgr = GridLayoutManager(context, spans)
if (shouldBeFullWidth != null) {
mgr.spanSizeLookup =
object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (shouldBeFullWidth(position)) spans else 1
}
}
}
layoutManager = mgr
}
}
/** Returns whether a recyclerview can scroll. */
fun RecyclerView.canScroll(): Boolean = computeVerticalScrollRange() > height
/**
* Disables drop shadows on a view programmatically in a version-compatible manner. This only works
* on Android 9 and above. Below that version, shadows will remain visible.
@ -113,9 +84,52 @@ private fun isUnderImpl(
val View.isRtl: Boolean
get() = layoutDirection == View.LAYOUT_DIRECTION_RTL
val Drawable.isRtl: Boolean
get() = DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL
val ViewBinding.context: Context
get() = root.context
var TextView.textSafe
get() = text
set(value) {
text = value
requestLayout()
}
/**
* Apply the recommended spans for a [RecyclerView].
*
* @param shouldBeFullWidth Optional callback for determining whether an item should be full-width,
* regardless of spans
*/
fun RecyclerView.applySpans(shouldBeFullWidth: ((Int) -> Boolean)? = null) {
val spans = resources.getInteger(R.integer.recycler_spans)
if (spans > 1) {
val mgr = GridLayoutManager(context, spans)
if (shouldBeFullWidth != null) {
mgr.spanSizeLookup =
object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (shouldBeFullWidth(position)) spans else 1
}
}
}
layoutManager = mgr
}
}
/** Returns whether a recyclerview can scroll. */
fun RecyclerView.canScroll(): Boolean = computeVerticalScrollRange() > height
/** Converts this color to a single-color [ColorStateList]. */
val @receiver:ColorRes Int.stateList
get() = ColorStateList.valueOf(this)
/**
* Resolve system bar insets in a version-aware manner. This can be used to apply padding to a view
* that properly follows all the frustrating changes that were made between 8-11.

View file

@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!-- This layout is re-used across all detail fragments. Do not add databinding. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
@ -75,4 +71,3 @@
app:layout_constraintStart_toEndOf="@+id/detail_play_button"
app:layout_constraintTop_toTopOf="@+id/detail_play_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -85,11 +82,11 @@
android:id="@+id/playback_seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_medium"
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"
@ -101,8 +98,8 @@
android:id="@+id/playback_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small_inv"
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="parent"
@ -125,10 +122,10 @@
android:id="@+id/playback_loop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:contentDescription="@string/desc_change_loop"
android:src="@drawable/ic_loop"
app:hasIndicator="true"
android:layout_marginStart="@dimen/spacing_medium"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
@ -149,12 +146,12 @@
style="@style/Widget.Auxio.FloatingActionButton.PlayPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_medium"
android:contentDescription="@string/desc_play_pause"
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"
android:layout_marginBottom="@dimen/spacing_medium"
tools:src="@drawable/ic_play" />
<org.oxycblt.auxio.playback.PlaybackButton
@ -172,14 +169,13 @@
android:id="@+id/playback_shuffle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle"
android:layout_marginEnd="@dimen/spacing_medium"
app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/playback_skip_next"
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!-- This layout is re-used across all detail fragments. Do not add databinding. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
@ -88,4 +84,3 @@
app:layout_constraintTop_toTopOf="@+id/detail_play_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -181,4 +178,3 @@
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -168,6 +166,4 @@
app:layout_constraintTop_toTopOf="@+id/playback_skip_next"
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,13 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!-- This layout is re-used across all detail fragments. Do not add databinding. -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.RoundableImageView
@ -92,4 +89,3 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
@ -96,4 +93,3 @@
tools:progress="70" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.RoundableImageView
@ -86,4 +84,3 @@
app:layout_constraintTop_toTopOf="@+id/detail_play_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -184,4 +181,3 @@
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
@ -95,4 +92,3 @@
tools:progress="70" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
@ -12,4 +9,3 @@
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main"
tools:layout="@layout/fragment_main" />
</layout>

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.recyclerview.widget.RecyclerView
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/accent_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -17,5 +15,3 @@
app:layout_constraintTop_toBottomOf="@+id/accent_header"
tools:itemCount="18"
tools:listitem="@layout/item_accent" />
</layout>

View file

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/spacing_small">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/excluded_recycler"
android:layout_width="match_parent"
@ -30,5 +29,4 @@
android:textAppearance="@style/TextAppearance.Auxio.TitleMidLarge"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</layout>
</LinearLayout>

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.recyclerview.widget.RecyclerView
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -14,5 +12,3 @@
app:layout_constraintTop_toBottomOf="@+id/accent_header"
tools:itemCount="5"
tools:listitem="@layout/item_tab" />
</layout>

View file

@ -1,14 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".settings.AboutFragment">
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:orientation="vertical">
android:orientation="vertical"
tools:context=".settings.AboutFragment">
<org.oxycblt.auxio.ui.EdgeAppBarLayout
android:id="@+id/about_appbar"
@ -158,11 +156,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawableStartCompat="@drawable/ic_album"
app:drawableTint="?attr/colorControlNormal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/about_licenses"
tools:text="Songs Loaded: 1616"
app:drawableTint="?attr/colorControlNormal" />
tools:text="Songs Loaded: 1616" />
<TextView
android:id="@+id/about_author"
@ -170,8 +168,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lbl_author"
app:drawableTint="?attr/colorControlNormal"
app:drawableStartCompat="@drawable/ic_artist"
app:drawableTint="?attr/colorControlNormal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/about_song_count" />
@ -179,5 +177,4 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.core.widget.NestedScrollView>
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</layout>
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".detail.DetailFragment">
<FrameLayout
android:id="@+id/bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -34,5 +31,4 @@
tools:listitem="@layout/item_detail" />
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</FrameLayout>
</layout>
</FrameLayout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".home.HomeFragment">
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -59,4 +56,3 @@
</org.oxycblt.auxio.home.EdgeFabContainer>
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</layout>

View file

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
<org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/home_recycler"
style="@style/Widget.Auxio.RecyclerView.WithAdaptiveFab"
android:layout_width="match_parent"
@ -11,4 +10,3 @@
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:listitem="@layout/item_artist" />
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainFragment">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -63,5 +60,3 @@
</FrameLayout>
</FrameLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackBarView">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
@ -68,4 +65,3 @@
tools:progress="70" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.PlaybackPanelFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/playback_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -170,4 +167,3 @@
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.queue.QueueFragment">
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout
android:id="@+id/queue_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -36,4 +33,3 @@
tools:listitem="@layout/item_queue_song" />
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</layout>

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -55,4 +53,3 @@
tools:listitem="@layout/item_song" />
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</layout>

View file

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".settings.SettingsFragment">
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout
<org.oxycblt.auxio.ui.EdgeCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/settings_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -33,4 +30,3 @@
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</org.oxycblt.auxio.ui.EdgeCoordinatorLayout>
</layout>

View file

@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".settings.pref.AccentAdapter.ViewHolder">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/spacing_small"
@ -22,5 +19,4 @@
tools:backgroundTint="?attr/colorPrimary"
tools:ignore="ContentDescription, SpeakableTextPresentCheck" />
</FrameLayout>
</layout>
</FrameLayout>

View file

@ -1,17 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.HeaderViewHolder">
<data>
<variable
name="header"
type="org.oxycblt.auxio.music.ActionHeader" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -20,7 +11,6 @@
style="@style/Widget.Auxio.TextView.Header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{context.getString(header.string)}"
app:layout_constraintBottom_toTopOf="@id/header_divider"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -31,16 +21,15 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:contentDescription="@{context.getString(header.desc)}"
android:minWidth="@dimen/size_btn_small"
android:minHeight="@dimen/size_btn_small"
android:background="@drawable/ui_unbounded_ripple"
android:paddingStart="@dimen/spacing_medium"
android:paddingEnd="@dimen/spacing_medium"
android:src="@{context.getDrawable(header.icon)}"
app:layout_constraintBottom_toTopOf="@id/header_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_sort" />
<com.google.android.material.divider.MaterialDivider
@ -50,4 +39,3 @@
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.AlbumViewHolder">
<data>
<variable
name="album"
type="org.oxycblt.auxio.music.Album" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_album_cover(album.resolvedName)}"
app:albumArt="@{album}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<TextView
android:id="@+id/album_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{album.rawName}"
app:layout_constraintBottom_toTopOf="@+id/album_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Album Name" />
<TextView
android:id="@+id/album_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:albumInfo="@{album}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toBottomOf="@+id/album_name"
tools:text="Artist / 10 Songs" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,25 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".detail.recycler.AlbumDetailAdapter.AlbumSongViewHolder">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
style="@style/Widget.Auxio.ItemLayout">
<ImageView
android:id="@+id/song_track_placeholder"
style="@style/Widget.Auxio.Image.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/def_track"
android:src="@drawable/ic_song"
android:visibility="gone"
android:visibility="invisible"
app:tint="@color/sel_accented"
app:layout_constraintBottom_toBottomOf="@+id/song_track"
app:layout_constraintEnd_toEndOf="@+id/song_track"
@ -31,33 +24,30 @@
android:id="@+id/song_track"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@{@string/desc_track_number(song.track)}"
android:gravity="center"
android:maxLines="1"
android:minWidth="@dimen/size_track_number"
android:text="@{@string/fmt_track(song.track)}"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
android:textColor="@color/sel_accented_secondary"
android:textSize="@dimen/text_size_ext_title_mid_larger"
android:textSize="@dimen/text_size_ext_title_mid_large"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/song_name"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1" />
tools:text="16" />
<TextView
android:id="@+id/song_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{song.resolvedName}"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/song_duration"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/song_track"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toTopOf="@+id/song_track"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
@ -66,13 +56,11 @@
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{song.formattedDuration}"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/song_track"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/song_track"
app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="16:16" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,23 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.ArtistViewHolder">
<data>
<variable
name="artist"
type="org.oxycblt.auxio.music.Artist" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/artist_image"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_artist_image(artist.resolvedName)}"
app:artistImage="@{artist}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -28,8 +18,7 @@
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{artist.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/artist_details"
app:layout_constraintBottom_toTopOf="@+id/artist_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/artist_image"
app:layout_constraintTop_toTopOf="parent"
@ -37,11 +26,10 @@
tools:text="Artist Name" />
<TextView
android:id="@+id/artist_details"
android:id="@+id/artist_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:artistInfo="@{artist}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/artist_image"
@ -49,4 +37,3 @@
tools:text="2 Albums, 20 Songs" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".detail.recycler.ArtistDetailAdapter.ArtistAlbumViewHolder">
<data>
<variable
name="album"
type="org.oxycblt.auxio.music.Album" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_album_cover(album.resolvedName)}"
app:albumArt="@{album}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<TextView
android:id="@+id/album_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{album.resolvedName}"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/album_year"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Album Name" />
<TextView
android:id="@+id/album_year"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{album.year != 0 ? String.valueOf(album.year) : @string/def_date}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toBottomOf="@+id/album_name"
tools:text="2020" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.SongViewHolder">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<TextView
android:id="@+id/song_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:text="@{song.resolvedName}"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/song_info"
app:layout_constraintEnd_toStartOf="@+id/song_duration"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
<TextView
android:id="@+id/song_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:text="@{song.resolvedAlbumName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/song_duration"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="Album" />
<TextView
android:id="@+id/song_duration"
style="@style/Widget.Auxio.TextView.Item.Tertiary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="none"
android:gravity="end"
android:text="@{song.formattedDuration}"
android:textAlignment="viewEnd"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="16:16" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!-- This layout is re-used across all detail fragments. Do not add databinding. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/spacing_medium">
@ -75,4 +72,3 @@
app:layout_constraintStart_toEndOf="@+id/detail_play_button"
app:layout_constraintTop_toTopOf="@+id/detail_play_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
style="@style/Widget.Auxio.ItemLayout"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout"
android:padding="0dp">
<TextView
@ -42,4 +41,3 @@
app:tint="?attr/colorControlNormal" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.GenreViewHolder">
<data>
<variable
name="genre"
type="org.oxycblt.auxio.music.Genre" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/genre_image"
style="@style/Widget.Auxio.Image.Medium"
android:contentDescription="@{@string/desc_genre_image(genre.resolvedName)}"
app:genreImage="@{genre}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_genre" />
<TextView
android:id="@+id/genre_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{genre.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/genre_count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/genre_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Genre Name" />
<TextView
android:id="@+id/genre_count"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:genreInfo="@{genre}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/genre_image"
app:layout_constraintTop_toBottomOf="@+id/genre_name"
tools:text="40 Songs" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".detail.recycler.GenreDetailAdapter.GenreSongViewHolder">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" />
<TextView
android:id="@+id/song_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:text="@{song.resolvedName}"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/song_info"
app:layout_constraintEnd_toStartOf="@+id/song_duration"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
<TextView
android:id="@+id/song_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/song_duration"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="Artist / Album" />
<TextView
android:id="@+id/song_duration"
style="@style/Widget.Auxio.TextView.Item.Tertiary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="none"
android:gravity="end"
android:text="@{song.formattedDuration}"
android:textAlignment="viewEnd"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="16:16" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,17 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.HeaderViewHolder">
<data>
<variable
name="header"
type="org.oxycblt.auxio.music.Header" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -20,7 +10,6 @@
style="@style/Widget.Auxio.TextView.Header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{context.getString(header.string)}"
app:layout_constraintBottom_toTopOf="@id/header_divider"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -33,4 +22,3 @@
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/parent_image"
style="@style/Widget.Auxio.Image.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_artist" />
<TextView
android:id="@+id/parent_name"
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/parent_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/parent_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Artist" />
<TextView
android:id="@+id/parent_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/parent_image"
app:layout_constraintTop_toBottomOf="@+id/parent_name"
tools:text="Info" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,17 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".playback.queue.QueueAdapter.QueueSongViewHolder">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface">
@ -39,11 +30,9 @@
android:background="?attr/colorSurface">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
android:id="@+id/song_album_cover"
style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_medium"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -55,10 +44,9 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
android:text="@{song.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/song_info"
app:layout_constraintEnd_toStartOf="@+id/song_drag_handle"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintStart_toEndOf="@+id/song_album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
@ -69,10 +57,9 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/song_drag_handle"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintStart_toEndOf="@+id/song_album_cover"
app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="Artist / Album" />
@ -89,10 +76,9 @@
android:paddingEnd="@dimen/spacing_medium"
android:scaleType="center"
android:src="@drawable/ic_handle"
app:layout_constraintBottom_toBottomOf="@+id/album_cover"
app:layout_constraintBottom_toBottomOf="@+id/song_album_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/album_cover" />
app:layout_constraintTop_toTopOf="@+id/song_album_cover" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</layout>

View file

@ -1,23 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.SongViewHolder">
<data>
<variable
name="song"
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/Widget.Auxio.ItemLayout">
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.coil.RoundableImageView
android:id="@+id/album_cover"
android:id="@+id/song_album_cover"
style="@style/Widget.Auxio.Image.Small"
android:contentDescription="@{@string/desc_album_cover(song.resolvedName)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -28,25 +17,23 @@
style="@style/Widget.Auxio.TextView.Item.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{song.resolvedName}"
android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/song_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintStart_toEndOf="@+id/song_album_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" />
tools:text="Song" />
<TextView
android:id="@+id/song_info"
style="@style/Widget.Auxio.TextView.Item.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:songInfo="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover"
app:layout_constraintStart_toEndOf="@+id/song_album_cover"
app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="Artist / Album" />
tools:text="Info" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
style="@style/Widget.Auxio.ItemLayout"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout"
android:padding="0dp">
<com.google.android.material.checkbox.MaterialCheckBox
@ -47,4 +46,3 @@
app:layout_constraintTop_toTopOf="@+id/tab_icon" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<merge
xmlns:tools="http://schemas.android.com/tools"
tools:layout_height="wrap_content"
tools:layout_width="match_parent"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
@ -50,4 +48,3 @@
tools:text="16:16" />
</merge>
</layout>

View file

@ -26,7 +26,6 @@
<dimen name="text_size_ext_label_larger">16sp</dimen>
<dimen name="text_size_ext_title_mid_large">18sp</dimen>
<dimen name="text_size_ext_title_mid_larger">20sp</dimen>
<!-- Misc -->
<dimen name="elevation_small">2dp</dimen>

View file

@ -6,5 +6,5 @@
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_two" translatable="false">%1$s • %2$s</string>
<string name="fmt_three" translatable="false">%1$s • %2$s • %3$s</string>
<string name="fmt_track" translatable="false">%d</string>
<string name="fmt_number" translatable="false">%d</string>
</resources>

View file

@ -44,16 +44,16 @@ should be added as a new `Fragment` implementation and added to one of the two n
- `nav_main`: Navigation *from* `MainFragment`
- `nav_explore`: Navigation *in* `MainFragment`
Fragments themselves are organized in order of lifecycle. So the first override would be `onCreate`, followed by
`onCreateView`, and so on. `onCreateView` is where all view instantiation and configuration takes place, and
is separated into three phases:
Fragments themselves are based off a super class called `ViewBindingFragment` that takes a view-binding and then
leverages it within the fragment lifecycle.
- Create variables [Bindings, Adapters, etc]
- Set up the UI
- Set up ViewModel instances and LiveData observers
`findViewById` is to **only** be used when interfacing with non-Auxio views. Otherwise, view-binding should be
used in all cases. Avoid usages of databinding outside of the `onCreateView` step unless absolutely necessary.
used in all cases. Code that involves retrieving the binding should be isolated into its own function, with
the binding being obtained by calling `requireBinding`.
At times it may be more appropriate to use a `View` instead of a full blown fragment. This is okay as long as
view-binding is still used.
@ -62,11 +62,6 @@ When creating a ViewHolder for a `RecyclerView`, one should use `BaseViewHolder`
and automate some code shared across all ViewHolders. The only exceptions to this case are for ViewHolders that
correspond to non-`BaseModel` data, in which a normal ViewHolder can be used instead.
Data is often bound using Binding Adapters, which are XML attributes assigned in layout files that can automatically
display data, usually written as `app:bindingAdapterName="@{data}"`. Its recommended to use these instead of applying
the attributes directly unless absolutely necessary. Usually it's okay to apply data programmatically if you begin
to duplicate layouts simply because they apply to different data objects, such as the detail UIs.
#### Object communication
Auxio's codebase is mostly centered around 4 different types of code that communicates with each-other.