image: add image group

Add a new view called ImageGroup that will handle all advanced image
hacks from now on.

This includes the indicator (which is now animated), any selection
indicators, and the weirdness of the album song image. All of that
is now handled by ImageGroup. This is the culmination of probably
a day and a half of wrangling with android insanity and having to
remove a lot of what I liked about the indicator in order to make
this work on a basic level.

The only major bug I am currently aware of with this is that the
indicator is bugged out on Lollipop devices due to bad vectors.
Again.

I never want to do this again. I cannot believe that adding a basic
indicator took this long and required so much stupid hacks and
inefficient code. And then google wonders why android apps are so
visually unappealing and janky and laggy. Hm. Must be that devs aren't
using the brand new FooBarBlasterFlow library!
This commit is contained in:
OxygenCobalt 2022-06-10 11:57:50 -06:00
parent ffe7298665
commit d80c49f11f
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
33 changed files with 993 additions and 161 deletions

View file

@ -5,6 +5,7 @@
#### What's New #### What's New
- Folders on external drives can now be excluded on Android Q+ [#134] - Folders on external drives can now be excluded on Android Q+ [#134]
- Playback bar now has a skip action - Playback bar now has a skip action
- When playing, the cover now shows an animated indicator
#### What's Improved #### What's Improved
- The toolbar in the home UI now collapses when scrolling - The toolbar in the home UI now collapses when scrolling

View file

@ -209,7 +209,6 @@ class AlbumDetailFragment : DetailFragment(), AlbumDetailAdapter.Listener {
} }
if (parent is Album && parent.id == unlikelyToBeNull(detailModel.currentAlbum.value).id) { if (parent is Album && parent.id == unlikelyToBeNull(detailModel.currentAlbum.value).id) {
logD("update $song")
detailAdapter.highlightSong(song) detailAdapter.highlightSong(song)
} else { } else {
// Clear the ViewHolders if the mode isn't ALL_SONGS // Clear the ViewHolders if the mode isn't ALL_SONGS

View file

@ -31,7 +31,6 @@ import org.oxycblt.auxio.ui.BindingViewHolder
import org.oxycblt.auxio.ui.Item import org.oxycblt.auxio.ui.Item
import org.oxycblt.auxio.ui.MenuItemListener import org.oxycblt.auxio.ui.MenuItemListener
import org.oxycblt.auxio.ui.SimpleItemCallback import org.oxycblt.auxio.ui.SimpleItemCallback
import org.oxycblt.auxio.ui.StyledImageView
import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.formatDuration import org.oxycblt.auxio.util.formatDuration
import org.oxycblt.auxio.util.getPluralSafe import org.oxycblt.auxio.util.getPluralSafe
@ -194,21 +193,12 @@ private class AlbumSongViewHolder private constructor(private val binding: ItemA
isInvisible = false isInvisible = false
contentDescription = context.getString(R.string.desc_track_number, item.track) contentDescription = context.getString(R.string.desc_track_number, item.track)
} }
binding.songTrackBg.setImageDrawable(null)
} else { } else {
binding.songTrack.apply { binding.songTrack.apply {
textSafe = "" textSafe = ""
isInvisible = true isInvisible = true
contentDescription = context.getString(R.string.def_track) contentDescription = context.getString(R.string.def_track)
} }
// Normally we would not re-load the drawable each time and instead
// change the alpha value, but Lollipop gets in our way yet again
// and does some stupid insanity with the alpha value that results
// in such branching.
binding.songTrackBg.setImageDrawable(
StyledImageView.StyledDrawable(binding.context, R.drawable.ic_song))
} }
binding.songName.textSafe = item.resolveName(binding.context) binding.songName.textSafe = item.resolveName(binding.context)

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.ui package org.oxycblt.auxio.image
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
@ -25,111 +25,67 @@ import android.graphics.drawable.Drawable
import android.util.AttributeSet import android.util.AttributeSet
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import coil.dispose import coil.dispose
import coil.drawable.CrossfadeDrawable
import coil.load import coil.load
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.SquareFrameTransform
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.getColorStateListSafe import org.oxycblt.auxio.util.getColorStateListSafe
import org.oxycblt.auxio.util.getDrawableSafe import org.oxycblt.auxio.util.getDrawableSafe
/** /**
* An [AppCompatImageView] that applies many of the stylistic choices that Auxio uses regarding * The base class for Auxio's images. Do not use this class outside of this module.
* images. *
* Default behavior includes the addition of a tonal background and automatic icon sizing. Other
* behavior is implemented by [StyledImageView] and [ImageGroup].
* *
* Default behavior includes the addition of a tonal background, automatic sizing of icons to half
* of the view size, and corner radius application depending on user preference.
* @author OxygenCobalt * @author OxygenCobalt
*
* TODO: I'll need to make it a whole ViewGroup eventually
*/ */
class StyledImageView open class BaseStyledImageView
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
AppCompatImageView(context, attrs, defStyleAttr) { AppCompatImageView(context, attrs, defStyleAttr) {
private var cornerRadius = 0f private var staticIcon = 0
private var indicator = StyledDrawable(context, R.drawable.ic_equalizer)
init { init {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView) val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView)
cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f) staticIcon = styledAttrs.getResourceId(R.styleable.StyledImageView_staticIcon, -1)
styledAttrs.recycle() styledAttrs.recycle()
// Use clipToOutline and a background drawable to crop images. While Coil's transformation
// could theoretically be used to round corners, the corner radius is dependent on the
// dimensions of the image, which will result in inconsistent corners across different
// album covers unless we resize all covers to be the same size. clipToOutline is both
// cheaper and more elegant. As a side-note, this also allows us to re-use the same
// background for both the tonal background color and the corner rounding.
clipToOutline = true
background = background =
MaterialShapeDrawable().apply { MaterialShapeDrawable().apply {
fillColor = context.getColorStateListSafe(R.color.sel_cover_bg) fillColor = context.getColorStateListSafe(R.color.sel_cover_bg)
} }
// If we have a pre-set drawable, ensure that it's half-size.
val drawable = drawable
if (drawable != null) {
setImageDrawable(StyledDrawable(context, drawable))
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (isActivated) {
// We can't modify the view alpha since that would change the background opacity,
// but we also can't modify the image alpha since that breaks CrossfadeDrawable.
// Instead, we just draw the background again when activated in order to obscure
// the actual image, and then draw the indicator. The only other option is to make
// a proper ViewGroup, and I really don't want that.
val src = drawable?.let { if (it is CrossfadeDrawable) it.end else it }
background.alpha = if (src is StyledDrawable) 255 else 128
background.draw(canvas)
background.alpha = 255
indicator.draw(canvas)
}
} }
/** Bind the album cover for a [song]. */ /** Bind the album cover for a [song]. */
fun bind(song: Song) = loadImpl(song, R.drawable.ic_song, R.string.desc_album_cover) open fun bind(song: Song) = loadImpl(song, R.drawable.ic_song)
/** Bind the album cover for an [album]. */ /** Bind the album cover for an [album]. */
fun bind(album: Album) = loadImpl(album, R.drawable.ic_album, R.string.desc_album_cover) open fun bind(album: Album) = loadImpl(album, R.drawable.ic_album)
/** Bind the image for an [artist] */ /** Bind the image for an [artist] */
fun bind(artist: Artist) = loadImpl(artist, R.drawable.ic_artist, R.string.desc_artist_image) open fun bind(artist: Artist) = loadImpl(artist, R.drawable.ic_artist)
/** Bind the image for a [genre] */ /** Bind the image for a [genre] */
fun bind(genre: Genre) = loadImpl(genre, R.drawable.ic_genre, R.string.desc_genre_image) open fun bind(genre: Genre) = loadImpl(genre, R.drawable.ic_genre)
private fun <T : Music> loadImpl(music: T, @DrawableRes error: Int) {
if (staticIcon > -1) {
throw IllegalStateException("Static StyledImageViews cannot bind new images")
}
private fun <T : Music> loadImpl(music: T, @DrawableRes error: Int, @StringRes desc: Int) {
dispose() dispose()
load(music) { load(music) {
error(StyledDrawable(context, error)) error(StyledDrawable(context, error))
transformations(SquareFrameTransform.INSTANCE) transformations(SquareFrameTransform.INSTANCE)
} }
contentDescription = context.getString(desc, music.resolveName(context))
} }
/** /**

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.AttrRes
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.getColorStateListSafe
/**
* Effectively a super-charged [StyledImageView].
*
* This class enables the following features alongside the base features pf [StyledImageView]:
* - Activation indicator with an animated icon
* - (Eventually) selection indicator
* - Support for ONE custom view
*
* This class is primarily intended for list items. For most uses, the simpler [StyledImageView] is
* more efficient and suitable.
*
* @author OxygenCobalt
*/
class ImageGroup
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
FrameLayout(context, attrs, defStyleAttr) {
private val cornerRadius: Float
private val inner = BaseStyledImageView(context, attrs)
private var customView: View? = null
private val indicator = ImageGroupIndicator(context)
init {
// Android wants you to make separate attributes for each view type, but will
// then throw an error if you do because of duplicate attribute names.
@SuppressLint("CustomViewStyleable")
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView)
cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f)
styledAttrs.recycle()
addView(inner)
// Use clipToOutline and a background drawable to crop images. While Coil's transformation
// could theoretically be used to round corners, the corner radius is dependent on the
// dimensions of the image, which will result in inconsistent corners across different
// album covers unless we resize all covers to be the same size. clipToOutline is both
// cheaper and more elegant. As a side-note, this also allows us to re-use the same
// background for both the tonal background color and the corner rounding.
background = MaterialShapeDrawable()
clipToOutline = true
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
}
override fun onFinishInflate() {
super.onFinishInflate()
if (childCount > 2) {
error("Only one custom view is allowed")
}
customView =
getChildAt(1)?.apply {
background =
MaterialShapeDrawable().apply {
fillColor = context.getColorStateListSafe(R.color.sel_cover_bg)
}
}
addView(indicator)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
invalidateIndicator()
}
override fun setActivated(activated: Boolean) {
super.setActivated(activated)
invalidateIndicator()
}
private fun invalidateIndicator() {
if (isActivated) {
indicator.alpha = 1f
customView?.alpha = 0f
inner.alpha = 0f
} else {
indicator.alpha = 0f
customView?.alpha = 1f
inner.alpha = 1f
}
}
fun bind(song: Song) {
inner.bind(song)
contentDescription =
context.getString(R.string.desc_album_cover, song.album.resolveName(context))
}
fun bind(album: Album) {
inner.bind(album)
contentDescription =
context.getString(R.string.desc_album_cover, album.resolveName(context))
}
fun bind(artist: Artist) {
inner.bind(artist)
contentDescription =
context.getString(R.string.desc_artist_image, artist.resolveName(context))
}
fun bind(genre: Genre) {
inner.bind(genre)
contentDescription =
context.getString(R.string.desc_genre_image, genre.resolveName(context))
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import android.content.Context
import android.graphics.Matrix
import android.graphics.RectF
import android.graphics.drawable.AnimationDrawable
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.getColorStateListSafe
/**
* Represents the animated indicator that is shown when [ImageGroup] is active.
*
* AnimationDrawable, the drawable that this view is backed by, is really finicky. Basically, it has
* to be set as the drawable of an ImageView to work correctly, and will just not draw anywhere
* else. As a result, we have to create a custom view that emulates [StyledImageView] and
* [StyledDrawable] simultaneously while also managing the animation state.
*
* @author OxygenCobalt
*/
class ImageGroupIndicator
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
AppCompatImageView(context, attrs, defStyleAttr) {
private val centerMatrix = Matrix()
private val matrixSrc = RectF()
private val matrixDst = RectF()
init {
scaleType = ScaleType.MATRIX
setImageResource(R.drawable.ic_animated_equalizer)
imageTintList = context.getColorStateListSafe(R.color.sel_on_cover_bg)
background =
MaterialShapeDrawable().apply {
fillColor = context.getColorStateListSafe(R.color.sel_cover_bg)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// Instead of using StyledDrawable (which would break the animation), we scale
// up the animated icon using a matrix. This is okay, as it won't fall victim to
// the same issues that come with using a matrix in StyledImageView
imageMatrix =
centerMatrix.apply {
reset()
drawable?.let { drawable ->
// Android is too good to allow us to set a fixed image size, so we instead need
// to define a matrix to scale an image directly.
val iconWidth = measuredWidth / 2f
val iconHeight = measuredHeight / 2f
// First scale the icon up to the desired size.
matrixSrc.set(
0f,
0f,
drawable.intrinsicWidth.toFloat(),
drawable.intrinsicHeight.toFloat())
matrixDst.set(0f, 0f, iconWidth, iconHeight)
centerMatrix.setRectToRect(matrixSrc, matrixDst, Matrix.ScaleToFit.CENTER)
// Then actually center it into the icon, which the previous call does not
// actually do.
centerMatrix.postTranslate(
(measuredWidth - iconWidth) / 2f, (measuredHeight - iconHeight) / 2f)
}
}
}
override fun setActivated(activated: Boolean) {
super.setActivated(activated)
val icon = drawable as AnimationDrawable
if (activated) {
icon.start()
} else {
icon.stop()
}
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import android.content.Context
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import androidx.core.graphics.drawable.DrawableCompat
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.getColorStateListSafe
/**
* The internal drawable used by Auxio's images. Do not use this outside of this module.
*
* This enables a few features:
* - Automatic tinting to the correct image tint
* - Automatic sizing to HALF of the canvas.
*
* @author OxygenCobalt
*/
class StyledDrawable(context: Context, private val src: Drawable) : Drawable() {
init {
// Re-tint the drawable to something that will play along with the background.
// Done here because this call (and nothing else) miraculously works on Lollipop devices
DrawableCompat.setTintList(src, context.getColorStateListSafe(R.color.sel_on_cover_bg))
}
override fun draw(canvas: Canvas) {
src.bounds.set(canvas.clipBounds)
val adjustWidth = src.bounds.width() / 4
val adjustHeight = src.bounds.height() / 4
src.bounds.set(
adjustWidth,
adjustHeight,
src.bounds.width() - adjustWidth,
src.bounds.height() - adjustHeight)
src.draw(canvas)
}
override fun setAlpha(alpha: Int) {
src.alpha = alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
src.colorFilter = colorFilter
}
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
/**
* An [AppCompatImageView] that applies many of the stylistic choices that Auxio uses regarding
* images.
*
* Default behavior includes the addition of a tonal background, automatic sizing of icons to half
* of the view size, and corner radius application depending on user preference.
*
* @author OxygenCobalt
*/
class StyledImageView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
BaseStyledImageView(context, attrs, defStyleAttr) {
private var cornerRadius = 0f
init {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView)
cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f)
styledAttrs.recycle()
// Use clipToOutline and a background drawable to crop images. While Coil's transformation
// could theoretically be used to round corners, the corner radius is dependent on the
// dimensions of the image, which will result in inconsistent corners across different
// album covers unless we resize all covers to be the same size. clipToOutline is both
// cheaper and more elegant. As a side-note, this also allows us to re-use the same
// background for both the tonal background color and the corner rounding.
clipToOutline = true
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
}
override fun bind(song: Song) {
super.bind(song)
contentDescription =
context.getString(R.string.desc_album_cover, song.album.resolveName(context))
}
override fun bind(album: Album) {
super.bind(album)
contentDescription =
context.getString(R.string.desc_album_cover, album.resolveName(context))
}
override fun bind(artist: Artist) {
super.bind(artist)
contentDescription =
context.getString(R.string.desc_artist_image, artist.resolveName(context))
}
override fun bind(genre: Genre) {
super.bind(genre)
contentDescription =
context.getString(R.string.desc_genre_image, genre.resolveName(context))
}
}

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.ui package org.oxycblt.auxio.playback
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/transparent" android:state_activated="true" />
<item android:color="?attr/colorSurfaceInverse" />
</selector>

View file

@ -0,0 +1,491 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<!--
Yes, this whole file is all 30 frames of Spotify's equalizer animation,
modified to look like the material equalizer icon, and inlined into an
animation list using aapt:attr so that it doesn't clutter the drawable
field. It looks better than if I did it programmatically, though.
-->
<!-- Frame 1 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064 3.9997559 L 9.9999064 19.999813 L 14.000179 19.999813 L 14.000179 3.9997559 L 9.9999064 3.9997559 z M 3.9997559 10.999845 L 3.9997559 19.999813 L 8.0000285 19.999813 L 8.0000285 10.999845 L 3.9997559 10.999845 z M 16.000057 10.999845 L 16.000057 19.999813 L 19.999813 19.999813 L 19.999813 10.999845 L 16.000057 10.999845 z " />
</vector>
</aapt:attr>
</item>
<!-- Frame 2 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064 5.0002116 L 9.9999064 19.999813 L 14.000179 19.999813 L 14.000179 5.0002116 L 9.9999064 5.0002116 z M 3.9997559 9.9999064 L 3.9997559 19.999813 L 8.0000285 19.999813 L 8.0000285 9.9999064 L 3.9997559 9.9999064 z M 16.000057 14.000179 L 16.000057 19.999813 L 19.999813 19.999813 L 19.999813 14.000179 L 16.000057 14.000179 z " />
</vector>
</aapt:attr>
</item>
<!-- Frame 3 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,5.0002116 V 19.999813 H 14.000179 V 5.0002116 Z M 3.9997559,9 V 19.999813 H 8.0000285 V 9 Z m 12.0003011,7 v 3.999813 h 3.999756 V 16 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 4 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,7 V 19.999813 H 14.000179 V 7 Z m -6.0001505,4 v 8.999813 H 8.0000285 V 11 Z m 12.0003011,6 v 2.999813 h 3.999756 V 17 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 5 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,9 V 19.999813 H 14.000179 V 9 Z m -6.0001505,1 v 9.999813 H 8.0000285 V 10 Z M 16,18 l 5.7e-5,1.999813 h 3.999756 V 18 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 6 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,11 v 8.999813 H 14.000179 V 11 Z M 3.9997559,9 V 19.999813 H 8.0000285 V 9 Z M 16,18 l 5.7e-5,1.999813 h 3.999756 V 18 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 7 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,13 v 6.999813 H 14.000179 V 13 Z M 3.9997559,8 V 19.999813 H 8.0000285 V 8 Z M 16,18 l 5.7e-5,1.999813 h 3.999756 V 18 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 8 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,16 v 3.999813 H 14.000179 V 16 Z M 3.9997559,7 V 19.999813 H 8.0000285 V 7 Z M 16,17 l 5.7e-5,2.999813 h 3.999756 V 17 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 9 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,17 v 2.999813 H 14.000179 V 17 Z M 3.9997559,6 V 19.999813 H 8.0000285 V 6 Z M 16,17 l 5.7e-5,2.999813 h 3.999756 V 17 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 10 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,18 v 1.999813 H 14.000179 V 18 Z M 3.9997559,5 V 19.999813 H 8.0000285 V 5 Z M 16,15 l 5.7e-5,4.999813 h 3.999756 V 15 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 11 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,18 v 1.999813 H 14.000179 V 18 Z M 3.9997559,5 V 19.999813 H 8.0000285 V 5 Z M 16,14 l 5.7e-5,5.999813 h 3.999756 V 14 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 12 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,17 v 2.999813 H 14.000179 V 17 Z M 3.9997559,4 V 19.999813 H 8.0000285 V 4 Z M 16,12 l 5.7e-5,7.999813 h 3.999756 V 12 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 13 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,17 v 2.999813 H 14.000179 V 17 Z M 3.9997559,4 V 19.999813 H 8.0000285 V 4 Z M 16,11 l 5.7e-5,8.999813 h 3.999756 V 11 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 14 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,17 v 2.999813 H 14.000179 V 17 Z M 3.9997559,4 V 19.999813 H 8.0000285 V 4 Z M 16,10 l 5.7e-5,9.999813 h 3.999756 V 10 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 15 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,15 v 4.999813 H 14.000179 V 15 Z M 3.9997559,5 V 19.999813 H 8.0000285 V 5 Z M 16,10 l 5.7e-5,9.999813 h 3.999756 V 10 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 16 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,14 v 5.999813 H 14.000179 V 14 Z M 3.9997559,5 V 19.999813 H 8.0000285 V 5 Z M 16,9 l 5.7e-5,10.999813 h 3.999756 V 9 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 17 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,12 v 7.999813 H 14.000179 V 12 Z M 3.9997559,7 V 19.999813 H 8.0000285 V 7 Z M 16,10 l 5.7e-5,9.999813 h 3.999756 V 10 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 18 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,10 v 9.999813 H 14.000179 V 10 Z M 4,10 3.9997559,19.999813 H 8.0000285 V 10 Z m 12,-1 5.7e-5,10.999813 h 3.999756 V 9 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 19 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,10 v 9.999813 H 14.000179 V 10 Z M 4,13 3.9997559,19.999813 H 8.0000285 V 13 Z m 12,-4 5.7e-5,10.999813 h 3.999756 V 9 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 20 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,9 V 19.999813 H 14.000179 V 9 Z M 4,15 3.9997559,19.999813 H 8.0000285 V 15 Z m 12,-7 5.7e-5,11.999813 h 3.999756 V 8 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 21 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 9.9999064,10 v 9.999813 H 14.000179 V 10 Z M 4,17 3.9997559,19.999813 H 8.0000285 V 17 Z m 12,-10 5.7e-5,12.999813 h 3.999756 V 7 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 22 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,9 V 19.999813 H 14.000179 V 9 Z M 4,17 3.9997559,19.999813 H 8.0000285 V 17 Z m 12,-11 5.7e-5,13.999813 h 3.999756 V 6 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 23 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,9 V 19.999813 H 14.000179 V 9 Z M 4,18 3.9997559,19.999813 H 8.0000285 V 18 Z m 12,-13 5.7e-5,14.999813 h 3.999756 V 5 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 24 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,9 V 19.999813 H 14.000179 V 9 Z M 4,18 3.9997559,19.999813 H 8.0000285 V 18 Z m 12,-13 5.7e-5,14.999813 h 3.999756 V 5 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 25 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 9.9999064,8 V 19.999813 H 14.000179 V 8 Z M 4,17 3.9997559,19.999813 H 8.0000285 V 17 Z m 12,-13 5.7e-5,15.999813 h 3.999756 V 4 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 26 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 10,7 -9.36e-5,12.999813 H 14.000179 L 14,7 Z M 4,17 3.9997559,19.999813 H 8.0000285 V 17 Z m 12,-13 5.7e-5,15.999813 h 3.999756 V 4 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 27 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 10,6 -9.36e-5,13.999813 H 14.000179 L 14,6 Z M 4,16 3.9997559,19.999813 H 8.0000285 V 16 Z m 12,-11 5.7e-5,14.999813 h 3.999756 V 5 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 28 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 10,5 -9.36e-5,14.999813 H 14.000179 L 14,5 Z m -6,9 -2.441e-4,5.999813 H 8.0000285 V 14 Z m 12,-9 5.7e-5,14.999813 h 3.999756 V 5 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 29 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 10,5 -9.36e-5,14.999813 H 14.000179 L 14,5 Z m -6,8 -2.441e-4,6.999813 H 8.0000285 V 13 Z m 12,-7 5.7e-5,13.999813 h 3.999756 V 6 Z" />
</vector>
</aapt:attr>
</item>
<!-- Frame 30 -->
<item android:duration="30">
<aapt:attr name="android:drawable">
<vector
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m 10,4 -9.36e-5,15.999813 H 14.000179 L 14,4 Z m -6,7 -2.441e-4,8.999813 H 8.0000285 V 11 Z m 12,-2 5.7e-5,10.999813 h 3.999756 V 9 Z" />
</vector>
</aapt:attr>
</item>
</animation-list>

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M10,20h4L14,4h-4v16zM4,20h4v-8L4,12v8zM16,9v11h4L20,9h-4z"/>
</vector>

View file

@ -6,14 +6,14 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/detail_cover" android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Huge" style="@style/Widget.Auxio.Image.Huge"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/detail_name" android:id="@+id/detail_name"

View file

@ -14,7 +14,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_marginStart="@dimen/spacing_medium" android:layout_marginStart="@dimen/spacing_medium"
@ -86,7 +86,7 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -136,7 +136,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -6,13 +6,13 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/detail_cover" android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Large" style="@style/Widget.Auxio.Image.Large"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/detail_name" android:id="@+id/detail_name"

View file

@ -14,7 +14,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large" android:layout_margin="@dimen/spacing_mid_large"
@ -84,7 +84,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_cover" app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_album" /> app:layout_constraintTop_toBottomOf="@+id/playback_album" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -135,7 +135,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -15,7 +15,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large" android:layout_margin="@dimen/spacing_mid_large"
@ -73,7 +73,7 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -124,7 +124,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -7,14 +7,14 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/detail_cover" android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.MidHuge" style="@style/Widget.Auxio.Image.MidHuge"
app:layout_constraintDimensionRatio="1" app:layout_constraintDimensionRatio="1"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/detail_name" android:id="@+id/detail_name"

View file

@ -6,7 +6,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Medium" style="@style/Widget.Auxio.Image.Medium"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"

View file

@ -6,13 +6,13 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/detail_cover" android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.Huge" style="@style/Widget.Auxio.Image.Huge"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/detail_name" android:id="@+id/detail_name"

View file

@ -15,7 +15,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_medium" android:layout_margin="@dimen/spacing_medium"
@ -87,7 +87,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_cover" app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_album" /> app:layout_constraintTop_toBottomOf="@+id/playback_album" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -139,7 +139,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -6,7 +6,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Small" style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"

View file

@ -14,7 +14,7 @@
app:title="@string/lbl_playback" app:title="@string/lbl_playback"
tools:subtitle="@string/lbl_all_songs" /> tools:subtitle="@string/lbl_all_songs" />
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/playback_cover" android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full" style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_medium" android:layout_margin="@dimen/spacing_medium"
@ -22,7 +22,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar" app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
tools:src="@drawable/ic_album" /> tools:placeholderIcon="@drawable/ic_song" />
<TextView <TextView
android:id="@+id/playback_song" android:id="@+id/playback_song"
@ -70,7 +70,7 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -120,7 +120,7 @@
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.ui.IndicatorMaterialButton <org.oxycblt.auxio.playback.IndicatorMaterialButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
style="@style/Widget.Auxio.Button.Icon.Large" style="@style/Widget.Auxio.Button.Icon.Large"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -11,34 +11,36 @@
view. The way we do this is odd, but it's designed this way. view. The way we do this is odd, but it's designed this way.
--> -->
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.ImageGroup
android:id="@+id/song_track_bg" android:id="@+id/song_track_bg"
style="@style/Widget.Auxio.Image.Small" style="@style/Widget.Auxio.Image.Small"
android:scaleType="matrix"
app:layout_constraintBottom_toBottomOf="@+id/song_track"
app:layout_constraintEnd_toEndOf="@+id/song_track"
app:layout_constraintStart_toStartOf="@+id/song_track"
app:layout_constraintTop_toTopOf="@+id/song_track" />
<TextView
android:id="@+id/song_track"
android:layout_width="@dimen/size_btn_small"
android:layout_height="@dimen/size_btn_small"
android:gravity="center"
android:maxLines="1"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
android:textColor="@color/sel_track_cover"
app:autoSizeMaxTextSize="@dimen/text_size_track_number_max"
app:autoSizeMinTextSize="@dimen/text_size_track_number_min"
app:autoSizeStepGranularity="@dimen/text_size_track_number_step"
app:autoSizeTextType="uniform"
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_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="16" /> app:staticIcon="@drawable/ic_song"
tools:visibility="invisible">
<TextView
android:id="@+id/song_track"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:maxLines="1"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
android:textColor="@color/sel_on_cover_bg"
app:autoSizeMaxTextSize="@dimen/text_size_track_number_max"
app:autoSizeMinTextSize="@dimen/text_size_track_number_min"
app:autoSizeStepGranularity="@dimen/text_size_track_number_step"
app:autoSizeTextType="uniform"
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="16" />
</org.oxycblt.auxio.image.ImageGroup>
<TextView <TextView
android:id="@+id/song_name" android:id="@+id/song_name"
@ -48,8 +50,8 @@
android:textColor="@color/sel_accented_primary" android:textColor="@color/sel_accented_primary"
app:layout_constraintBottom_toTopOf="@+id/song_duration" app:layout_constraintBottom_toTopOf="@+id/song_duration"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/song_track" app:layout_constraintStart_toEndOf="@+id/song_track_bg"
app:layout_constraintTop_toTopOf="@+id/song_track" app:layout_constraintTop_toTopOf="@+id/song_track_bg"
app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_chainStyle="packed"
tools:text="Song Name" /> tools:text="Song Name" />
@ -59,9 +61,9 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toBottomOf="@+id/song_track" app:layout_constraintBottom_toBottomOf="@+id/song_track_bg"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/song_track" app:layout_constraintStart_toEndOf="@+id/song_track_bg"
app:layout_constraintTop_toBottomOf="@+id/song_name" app:layout_constraintTop_toBottomOf="@+id/song_name"
tools:text="16:16" /> tools:text="16:16" />

View file

@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout"> style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/artist_image" android:id="@+id/artist_image"
style="@style/Widget.Auxio.Image.Medium" style="@style/Widget.Auxio.Image.Medium"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/artist_name" android:id="@+id/artist_name"

View file

@ -7,14 +7,14 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/detail_cover" android:id="@+id/detail_cover"
style="@style/Widget.Auxio.Image.MidHuge" style="@style/Widget.Auxio.Image.MidHuge"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/detail_name" android:id="@+id/detail_name"

View file

@ -6,11 +6,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/disc_item" android:id="@+id/disc_item"
style="@style/Widget.Auxio.Image.Small" style="@style/Widget.Auxio.Image.Small"
android:scaleType="matrix" android:scaleType="matrix"
android:src="@drawable/ic_album" app:staticIcon="@drawable/ic_album"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"

View file

@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout"> style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.ImageGroup
android:id="@+id/parent_image" android:id="@+id/parent_image"
style="@style/Widget.Auxio.Image.Medium" style="@style/Widget.Auxio.Image.Medium"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_artist" /> tools:staticIcon="@drawable/ic_artist" />
<TextView <TextView
android:id="@+id/parent_name" android:id="@+id/parent_name"

View file

@ -27,14 +27,14 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/colorSurface"> android:background="?attr/colorSurface">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.StyledImageView
android:id="@+id/song_album_cover" android:id="@+id/song_album_cover"
style="@style/Widget.Auxio.Image.Small" style="@style/Widget.Auxio.Image.Small"
android:layout_margin="@dimen/spacing_medium" android:layout_margin="@dimen/spacing_medium"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" /> tools:staticIcon="@drawable/ic_album" />
<TextView <TextView
android:id="@+id/song_name" android:id="@+id/song_name"

View file

@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Auxio.ItemLayout"> style="@style/Widget.Auxio.ItemLayout">
<org.oxycblt.auxio.ui.StyledImageView <org.oxycblt.auxio.image.ImageGroup
android:id="@+id/song_album_cover" android:id="@+id/song_album_cover"
style="@style/Widget.Auxio.Image.Small" style="@style/Widget.Auxio.Image.Small"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_album" /> tools:staticIcon="@drawable/ic_album" />
<TextView <TextView
android:id="@+id/song_name" android:id="@+id/song_name"

View file

@ -1,28 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Widget.Auxio.Toolbar.Actions" parent="Widget.Auxio.Toolbar.Base"> <style name="Widget.Auxio.Toolbar.Actions" parent="Widget.Auxio.Toolbar.Base">
<item name="android:layout_marginEnd">@dimen/spacing_tiny_inv</item> <item name="android:layout_marginEnd">@dimen/spacing_tiny_inv</item>
</style> </style>
\
<style name="Widget.Auxio.Toolbar.Icon" parent="Widget.Auxio.Toolbar.Base"> <style name="Widget.Auxio.Toolbar.Icon" parent="Widget.Auxio.Toolbar.Base">
<item name="navigationIcon">@drawable/ic_back</item> <item name="navigationIcon">@drawable/ic_back</item>
<item name="android:layout_marginStart">@dimen/spacing_small_inv</item> <item name="android:layout_marginStart">@dimen/spacing_small_inv</item>
</style> </style>
\
<style name="Widget.Auxio.Toolbar.Icon.Actions" parent="Widget.Auxio.Toolbar.Actions"> <style name="Widget.Auxio.Toolbar.Icon.Actions" parent="Widget.Auxio.Toolbar.Actions">
<item name="navigationIcon">@drawable/ic_back</item> <item name="navigationIcon">@drawable/ic_back</item>
<item name="android:layout_marginStart">@dimen/spacing_small_inv</item> <item name="android:layout_marginStart">@dimen/spacing_small_inv</item>
</style> </style>
\
<style name="Widget.Auxio.Toolbar.Icon.Down" parent="Widget.Auxio.Toolbar.Base"> <style name="Widget.Auxio.Toolbar.Icon.Down" parent="Widget.Auxio.Toolbar.Base">
<item name="navigationIcon">@drawable/ic_down</item> <item name="navigationIcon">@drawable/ic_down</item>
<item name="android:layout_marginStart">@dimen/spacing_small_inv</item> <item name="android:layout_marginStart">@dimen/spacing_small_inv</item>
</style> </style>
\
<style name="Widget.Auxio.Toolbar.Icon.Down.Actions" parent="Widget.Auxio.Toolbar.Actions"> <style name="Widget.Auxio.Toolbar.Icon.Down.Actions" parent="Widget.Auxio.Toolbar.Actions">
<item name="navigationIcon">@drawable/ic_down</item> <item name="navigationIcon">@drawable/ic_down</item>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Widget.Auxio.Button.AppWidget.V31" parent="Widget.AppCompat.Button.Borderless"> <style name="Widget.Auxio.Button.AppWidget.V31" parent="Widget.AppCompat.Button.Borderless">
<item name="android:background">@drawable/ui_large_unbounded_ripple</item> <item name="android:background">@drawable/ui_large_unbounded_ripple</item>
</style> </style>

View file

@ -2,6 +2,7 @@
<resources> <resources>
<declare-styleable name="StyledImageView"> <declare-styleable name="StyledImageView">
<attr name="cornerRadius" format="dimension" /> <attr name="cornerRadius" format="dimension" />
<attr name="staticIcon" format="reference" />
</declare-styleable> </declare-styleable>
<declare-styleable name="IntListPreference"> <declare-styleable name="IntListPreference">