ui: rework custom ui components

Refactor the package structure and implementation of custom UI
components.
This commit is contained in:
OxygenCobalt 2022-05-21 14:38:15 -06:00
parent 61839405ce
commit 2d7dbd19cd
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
65 changed files with 342 additions and 324 deletions

View file

@ -6,6 +6,10 @@
- Added disc number support - Added disc number support
- Added ReplayGain support for below-reference volume tracks [i.e positive ReplayGain values] - Added ReplayGain support for below-reference volume tracks [i.e positive ReplayGain values]
- About screen now shows counts for multiple types of library items, alongside a total duration - About screen now shows counts for multiple types of library items, alongside a total duration
- New disc, track, song count, and duration sorting modes
### What's Improved
- The tab selector now hides itself when there is only one tab
#### What's Fixed #### What's Fixed
- Fixed incorrect ellipsizing on song items - Fixed incorrect ellipsizing on song items

View file

@ -21,11 +21,11 @@ import android.app.Application
import coil.ImageLoader import coil.ImageLoader
import coil.ImageLoaderFactory import coil.ImageLoaderFactory
import coil.request.CachePolicy import coil.request.CachePolicy
import org.oxycblt.auxio.coil.AlbumArtFetcher import org.oxycblt.auxio.image.AlbumArtFetcher
import org.oxycblt.auxio.coil.ArtistImageFetcher import org.oxycblt.auxio.image.ArtistImageFetcher
import org.oxycblt.auxio.coil.CrossfadeFactory import org.oxycblt.auxio.image.CrossfadeFactory
import org.oxycblt.auxio.coil.GenreImageFetcher import org.oxycblt.auxio.image.GenreImageFetcher
import org.oxycblt.auxio.coil.MusicKeyer import org.oxycblt.auxio.image.MusicKeyer
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
@Suppress("UNUSED") @Suppress("UNUSED")

View file

@ -42,13 +42,11 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
* *
* TODO: Custom language support * TODO: Custom language support
* *
* TODO: Rework menus [perhaps add multi-select]
*
* TODO: Rework some fragments to use listeners *even more*
*
* TODO: Fix how selection works in the RecyclerViews (doing it poorly right now) * TODO: Fix how selection works in the RecyclerViews (doing it poorly right now)
* *
* TODO: Rework padding ethos * TODO: Rework padding ethos
*
* @author OxygenCobalt
*/ */
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val playbackModel: PlaybackViewModel by viewModels() private val playbackModel: PlaybackViewModel by viewModels()

View file

@ -1,153 +0,0 @@
/*
* 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.coil
import android.content.Context
import android.graphics.Matrix
import android.graphics.RectF
import android.util.AttributeSet
import android.widget.ImageView
import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView
import coil.dispose
import coil.load
import com.google.android.material.shape.MaterialShapeDrawable
import kotlin.math.min
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.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.getColorStateListSafe
/**
* An [AppCompatImageView] that applies many of the stylistic choices that Auxio uses regarding
* images.
*/
class StyledImageView
@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()
private var cornerRadius = 0f
init {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageView)
cornerRadius = styledAttrs.getDimension(R.styleable.StyledImageView_cornerRadius, 0f)
styledAttrs.recycle()
clipToOutline = true
background =
MaterialShapeDrawable().apply {
fillColor = context.getColorStateListSafe(R.color.sel_cover_bg)
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// 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.
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// Scale the image down to half-size
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.
// First scale the icon up to the desired size.
val iconSize = min(measuredWidth, measuredHeight) / 2f
matrixSrc.set(
0f,
0f,
drawable.intrinsicWidth.toFloat(),
drawable.intrinsicHeight.toFloat())
matrixDst.set(0f, 0f, iconSize, iconSize)
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 - iconSize) / 2f, (measuredHeight - iconSize) / 2f)
}
}
}
}
// TODO: Borg the extension methods into the view
/** Bind the album cover for a [song]. */
fun StyledImageView.bindAlbumCover(song: Song) =
load(song, R.drawable.ic_song, R.string.desc_album_cover)
/** Bind the album cover for an [album]. */
fun StyledImageView.bindAlbumCover(album: Album) =
load(album, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the image for an [artist] */
fun StyledImageView.bindArtistImage(artist: Artist) =
load(artist, R.drawable.ic_artist, R.string.desc_artist_image)
/** Bind the image for a [genre] */
fun StyledImageView.bindGenreImage(genre: Genre) =
load(genre, R.drawable.ic_genre, R.string.desc_genre_image)
private fun <T : Music> StyledImageView.load(
music: T,
@DrawableRes error: Int,
@StringRes desc: Int
) {
contentDescription = context.getString(desc, music.resolveName(context))
dispose()
load(music) {
error(error)
transformations(SquareFrameTransform.INSTANCE)
listener(
onSuccess = { _, _ ->
// Using the matrix scale type will shrink the cover images, so set it back to
// the default scale type.
scaleType = ImageView.ScaleType.FIT_CENTER
},
onError = { _, _ ->
// Error icons need to be scaled correctly, so set it to the custom matrix
// that the ImageView applies
scaleType = ImageView.ScaleType.MATRIX
})
}
}

View file

@ -22,7 +22,6 @@ import androidx.core.view.isInvisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.databinding.ItemDiscHeaderBinding import org.oxycblt.auxio.databinding.ItemDiscHeaderBinding
@ -123,7 +122,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite
BindingViewHolder<Album, AlbumDetailAdapter.Listener>(binding.root) { BindingViewHolder<Album, AlbumDetailAdapter.Listener>(binding.root) {
override fun bind(item: Album, listener: AlbumDetailAdapter.Listener) { override fun bind(item: Album, listener: AlbumDetailAdapter.Listener) {
binding.detailCover.bindAlbumCover(item) binding.detailCover.bind(item)
binding.detailName.textSafe = item.resolveName(binding.context) binding.detailName.textSafe = item.resolveName(binding.context)
binding.detailSubhead.apply { binding.detailSubhead.apply {

View file

@ -21,8 +21,6 @@ import android.content.Context
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.coil.bindArtistImage
import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.databinding.ItemParentBinding import org.oxycblt.auxio.databinding.ItemParentBinding
import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.databinding.ItemSongBinding
@ -139,7 +137,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It
BindingViewHolder<Artist, DetailAdapter.Listener>(binding.root) { BindingViewHolder<Artist, DetailAdapter.Listener>(binding.root) {
override fun bind(item: Artist, listener: DetailAdapter.Listener) { override fun bind(item: Artist, listener: DetailAdapter.Listener) {
binding.detailCover.bindArtistImage(item) binding.detailCover.bind(item)
binding.detailName.textSafe = item.resolveName(binding.context) binding.detailName.textSafe = item.resolveName(binding.context)
// Get the genre that corresponds to the most songs in this artist, which would be // Get the genre that corresponds to the most songs in this artist, which would be
@ -181,7 +179,7 @@ private constructor(
private val binding: ItemParentBinding, private val binding: ItemParentBinding,
) : BindingViewHolder<Album, MenuItemListener>(binding.root), Highlightable { ) : BindingViewHolder<Album, MenuItemListener>(binding.root), Highlightable {
override fun bind(item: Album, listener: MenuItemListener) { override fun bind(item: Album, listener: MenuItemListener) {
binding.parentImage.bindAlbumCover(item) binding.parentImage.bind(item)
binding.parentName.textSafe = item.resolveName(binding.context) binding.parentName.textSafe = item.resolveName(binding.context)
binding.parentInfo.textSafe = binding.parentInfo.textSafe =
if (item.year != null) { if (item.year != null) {
@ -226,7 +224,7 @@ private constructor(
private val binding: ItemSongBinding, private val binding: ItemSongBinding,
) : BindingViewHolder<Song, MenuItemListener>(binding.root), Highlightable { ) : BindingViewHolder<Song, MenuItemListener>(binding.root), Highlightable {
override fun bind(item: Song, listener: MenuItemListener) { override fun bind(item: Song, listener: MenuItemListener) {
binding.songAlbumCover.bindAlbumCover(item) binding.songAlbumCover.bind(item)
binding.songName.textSafe = item.resolveName(binding.context) binding.songName.textSafe = item.resolveName(binding.context)
binding.songInfo.textSafe = item.album.resolveName(binding.context) binding.songInfo.textSafe = item.album.resolveName(binding.context)

View file

@ -21,8 +21,6 @@ import android.content.Context
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.coil.bindGenreImage
import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemDetailBinding
import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.databinding.ItemSongBinding
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
@ -114,7 +112,7 @@ class GenreDetailAdapter(listener: Listener) :
private class GenreDetailViewHolder private constructor(private val binding: ItemDetailBinding) : private class GenreDetailViewHolder private constructor(private val binding: ItemDetailBinding) :
BindingViewHolder<Genre, DetailAdapter.Listener>(binding.root) { BindingViewHolder<Genre, DetailAdapter.Listener>(binding.root) {
override fun bind(item: Genre, listener: DetailAdapter.Listener) { override fun bind(item: Genre, listener: DetailAdapter.Listener) {
binding.detailCover.bindGenreImage(item) binding.detailCover.bind(item)
binding.detailName.textSafe = item.resolveName(binding.context) binding.detailName.textSafe = item.resolveName(binding.context)
binding.detailSubhead.textSafe = binding.detailSubhead.textSafe =
binding.context.getPluralSafe(R.plurals.fmt_song_count, item.songs.size) binding.context.getPluralSafe(R.plurals.fmt_song_count, item.songs.size)
@ -146,7 +144,7 @@ private class GenreDetailViewHolder private constructor(private val binding: Ite
class GenreSongViewHolder private constructor(private val binding: ItemSongBinding) : class GenreSongViewHolder private constructor(private val binding: ItemSongBinding) :
BindingViewHolder<Song, MenuItemListener>(binding.root), Highlightable { BindingViewHolder<Song, MenuItemListener>(binding.root), Highlightable {
override fun bind(item: Song, listener: MenuItemListener) { override fun bind(item: Song, listener: MenuItemListener) {
binding.songAlbumCover.bindAlbumCover(item) binding.songAlbumCover.bind(item)
binding.songName.textSafe = item.resolveName(binding.context) binding.songName.textSafe = item.resolveName(binding.context)
binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context)
binding.root.apply { binding.root.apply {

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.coil package org.oxycblt.auxio.image
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap

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.coil package org.oxycblt.auxio.image
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap

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.coil package org.oxycblt.auxio.image
import android.content.Context import android.content.Context
import coil.ImageLoader import coil.ImageLoader

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.coil package org.oxycblt.auxio.image
import coil.decode.DataSource import coil.decode.DataSource
import coil.drawable.CrossfadeDrawable import coil.drawable.CrossfadeDrawable

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.coil package org.oxycblt.auxio.image
import android.graphics.Bitmap import android.graphics.Bitmap
import coil.size.Size import coil.size.Size

View file

@ -25,7 +25,6 @@ import androidx.core.view.updatePadding
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.MainNavigationAction
@ -104,7 +103,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
if (song != null) { if (song != null) {
val context = requireContext() val context = requireContext()
val binding = requireBinding() val binding = requireBinding()
binding.playbackCover.bindAlbumCover(song) binding.playbackCover.bind(song)
binding.playbackSong.textSafe = song.resolveName(context) binding.playbackSong.textSafe = song.resolveName(context)
binding.playbackInfo.textSafe = song.resolveIndividualArtistName(context) binding.playbackInfo.textSafe = song.resolveIndividualArtistName(context)
binding.playbackProgressBar.max = song.durationSecs.toInt() binding.playbackProgressBar.max = song.durationSecs.toInt()

View file

@ -28,7 +28,6 @@ import com.google.android.material.color.MaterialColors
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlin.math.max import kotlin.math.max
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
@ -176,7 +175,7 @@ class PlaybackPanelFragment :
val binding = requireBinding() val binding = requireBinding()
val context = requireContext() val context = requireContext()
binding.playbackCover.bindAlbumCover(song) binding.playbackCover.bind(song)
binding.playbackSong.textSafe = song.resolveName(context) binding.playbackSong.textSafe = song.resolveName(context)
binding.playbackArtist.textSafe = song.resolveIndividualArtistName(context) binding.playbackArtist.textSafe = song.resolveIndividualArtistName(context)
binding.playbackAlbum.textSafe = song.album.resolveName(context) binding.playbackAlbum.textSafe = song.album.resolveName(context)
@ -186,7 +185,7 @@ class PlaybackPanelFragment :
binding.playbackDuration.textSafe = seconds.formatDuration(false) binding.playbackDuration.textSafe = seconds.formatDuration(false)
binding.playbackSeekBar.apply { binding.playbackSeekBar.apply {
isEnabled = seconds > 0L isEnabled = seconds > 0L
valueToSafe = max(seconds, 1L).toFloat() valueTo = max(seconds, 1L).toFloat()
} }
} }
@ -200,7 +199,7 @@ class PlaybackPanelFragment :
// around. // around.
val binding = requireBinding() val binding = requireBinding()
if (!binding.playbackPosition.isActivated) { if (!binding.playbackPosition.isActivated) {
binding.playbackSeekBar.valueSafe = position.toFloat() binding.playbackSeekBar.value = position.toFloat()
binding.playbackPosition.textSafe = position.formatDuration(true) binding.playbackPosition.textSafe = position.formatDuration(true)
} }
} }
@ -219,26 +218,4 @@ class PlaybackPanelFragment :
private fun updateShuffled(isShuffled: Boolean) { private fun updateShuffled(isShuffled: Boolean) {
requireBinding().playbackShuffle.isActivated = isShuffled requireBinding().playbackShuffle.isActivated = isShuffled
} }
private var Slider.valueSafe: Float
get() = value
set(v) {
value =
if (v > valueTo) {
valueTo
} else {
v
}
}
private var Slider.valueToSafe: Float
get() = valueTo
set(v) {
valueTo =
if (value > v) {
value
} else {
v
}
}
} }

View file

@ -28,7 +28,6 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.databinding.ItemQueueSongBinding import org.oxycblt.auxio.databinding.ItemQueueSongBinding
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.BackingData import org.oxycblt.auxio.ui.BackingData
@ -71,7 +70,7 @@ private constructor(
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun bind(item: Song, listener: QueueItemListener) { override fun bind(item: Song, listener: QueueItemListener) {
binding.songAlbumCover.bindAlbumCover(item) binding.songAlbumCover.bind(item)
binding.songName.textSafe = item.resolveName(binding.context) binding.songName.textSafe = item.resolveName(binding.context)
binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context)

View file

@ -25,7 +25,7 @@ import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat import android.support.v4.media.session.PlaybackStateCompat
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import org.oxycblt.auxio.coil.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.PlaybackStateManager

View file

@ -30,7 +30,7 @@ import androidx.media.app.NotificationCompat.MediaStyle
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode

View file

@ -19,7 +19,7 @@ package org.oxycblt.auxio.settings
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import org.oxycblt.auxio.accent.Accent import org.oxycblt.auxio.ui.accent.Accent
// A couple of utils for migrating from old settings values to the new formats // A couple of utils for migrating from old settings values to the new formats

View file

@ -30,12 +30,12 @@ import androidx.preference.children
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.Coil import coil.Coil
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.accent.AccentCustomizeDialog
import org.oxycblt.auxio.home.tabs.TabCustomizeDialog import org.oxycblt.auxio.home.tabs.TabCustomizeDialog
import org.oxycblt.auxio.music.excluded.ExcludedDialog import org.oxycblt.auxio.music.excluded.ExcludedDialog
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.pref.IntListPreference import org.oxycblt.auxio.settings.pref.IntListPreference
import org.oxycblt.auxio.settings.pref.IntListPreferenceDialog import org.oxycblt.auxio.settings.pref.IntListPreferenceDialog
import org.oxycblt.auxio.ui.accent.AccentCustomizeDialog
import org.oxycblt.auxio.util.hardRestart import org.oxycblt.auxio.util.hardRestart
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD

View file

@ -22,12 +22,12 @@ import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit import androidx.core.content.edit
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import org.oxycblt.auxio.accent.Accent
import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.system.ReplayGainMode import org.oxycblt.auxio.playback.system.ReplayGainMode
import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.Sort
import org.oxycblt.auxio.ui.accent.Accent
import org.oxycblt.auxio.util.unlikelyToBeNull import org.oxycblt.auxio.util.unlikelyToBeNull
/** /**

View file

@ -32,10 +32,11 @@ constructor(
defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle, defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle,
defStyleRes: Int = 0 defStyleRes: Int = 0
) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { ) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
// Reflect into Preference to get the (normally inaccessible) default value.
val entries: Array<CharSequence> val entries: Array<CharSequence>
val values: IntArray val values: IntArray
private var currentValue: Int? = null private var currentValue: Int? = null
// Reflect into Preference to get the (normally inaccessible) default value.
private val defValue: Int private val defValue: Int
get() = defValueField.get(this) as Int get() = defValueField.get(this) as Int

View file

@ -29,7 +29,7 @@ import org.oxycblt.auxio.util.getDrawableSafe
/** /**
* A [SwitchPreferenceCompat] that emulates the M3 switches until the design team actually bothers * A [SwitchPreferenceCompat] that emulates the M3 switches until the design team actually bothers
* to add them to MDC. * to add them to MDC TODO: Remove this once MaterialSwitch is stabilized.
*/ */
class M3SwitchPreference class M3SwitchPreference
@JvmOverloads @JvmOverloads
@ -45,7 +45,6 @@ constructor(
// Lollipop cannot into ColorStateList, disable this feature on that version // Lollipop cannot into ColorStateList, disable this feature on that version
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val switch = holder.findViewById(androidx.preference.R.id.switchWidget) val switch = holder.findViewById(androidx.preference.R.id.switchWidget)
if (switch is SwitchCompat) { if (switch is SwitchCompat) {
switch.apply { switch.apply {
trackDrawable = context.getDrawableSafe(R.drawable.ui_m3_switch_track) trackDrawable = context.getDrawableSafe(R.drawable.ui_m3_switch_track)

View file

@ -54,11 +54,9 @@ fun Fragment.newMenu(anchor: View, data: Item, flag: Int = ActionMenu.FLAG_NONE)
* @throws IllegalStateException When there is no menu for this specific datatype/flag * @throws IllegalStateException When there is no menu for this specific datatype/flag
* @author OxygenCobalt * @author OxygenCobalt
* *
* TODO: Stop scrolling when a menu is open
*
* TODO: Prevent duplicate menus from showing up * TODO: Prevent duplicate menus from showing up
* *
* TODO: Maybe replace this with a bottom sheet? * TODO: Add multi-select
*/ */
class ActionMenu( class ActionMenu(
activity: AppCompatActivity, activity: AppCompatActivity,

View file

@ -22,7 +22,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
/** A ViewModel that handles complicated navigation situations. */ /**
* A ViewModel that handles complicated navigation situations.
* @author OxygenCobalt
*/
class NavigationViewModel : ViewModel() { class NavigationViewModel : ViewModel() {
private val _mainNavigationAction = MutableLiveData<MainNavigationAction?>() private val _mainNavigationAction = MutableLiveData<MainNavigationAction?>()
/** Flag for main fragment navigation. Intended for MainFragment use only. */ /** Flag for main fragment navigation. Intended for MainFragment use only. */

View file

@ -28,6 +28,7 @@ import androidx.recyclerview.widget.RecyclerView
/** /**
* An adapter for one viewholder tied to one type of data. All functionality is derived from the * An adapter for one viewholder tied to one type of data. All functionality is derived from the
* overridden values. * overridden values.
* @author OxygenCobalt
*/ */
abstract class MonoAdapter<T, L, VH : BindingViewHolder<T, L>>(private val listener: L) : abstract class MonoAdapter<T, L, VH : BindingViewHolder<T, L>>(private val listener: L) :
RecyclerView.Adapter<VH>() { RecyclerView.Adapter<VH>() {
@ -51,6 +52,7 @@ private typealias AnyCreator = BindingViewHolder.Creator<out RecyclerView.ViewHo
/** /**
* An adapter for many viewholders tied to many types of data. Deriving this is more complicated * An adapter for many viewholders tied to many types of data. Deriving this is more complicated
* than [MonoAdapter], as less overrides can be provided "for free". * than [MonoAdapter], as less overrides can be provided "for free".
* @author OxygenCobalt
*/ */
abstract class MultiAdapter<L>(private val listener: L) : abstract class MultiAdapter<L>(private val listener: L) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
@ -99,6 +101,7 @@ abstract class MultiAdapter<L>(private val listener: L) :
* A variation of [RecyclerView.ViewHolder] that enables ViewBinding. This is be used to provide a * A variation of [RecyclerView.ViewHolder] that enables ViewBinding. This is be used to provide a
* universal surface for binding data to a ViewHolder, and can be used with [MonoAdapter] to get an * universal surface for binding data to a ViewHolder, and can be used with [MonoAdapter] to get an
* entire adapter implementation for free. * entire adapter implementation for free.
* @author OxygenCobalt
*/ */
abstract class BindingViewHolder<T, L>(root: View) : RecyclerView.ViewHolder(root) { abstract class BindingViewHolder<T, L>(root: View) : RecyclerView.ViewHolder(root) {
abstract fun bind(item: T, listener: L) abstract fun bind(item: T, listener: L)
@ -159,6 +162,7 @@ abstract class BackingData<T> {
/** /**
* A list-backed [BackingData] that is modified using adapter primitives. Useful in cases where * A list-backed [BackingData] that is modified using adapter primitives. Useful in cases where
* [AsyncBackingData] is not preferable due to bugs involving diffing. * [AsyncBackingData] is not preferable due to bugs involving diffing.
* @author OxygenCobalt
*/ */
class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : BackingData<T>() { class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : BackingData<T>() {
private var _currentList = mutableListOf<T>() private var _currentList = mutableListOf<T>()
@ -184,6 +188,7 @@ class PrimitiveBackingData<T>(private val adapter: RecyclerView.Adapter<*>) : Ba
* A list-backed [BackingData] that is modified with [AsyncListDiffer]. This is useful in cases * A list-backed [BackingData] that is modified with [AsyncListDiffer]. This is useful in cases
* where data updates are rapid-fire and unpredictable, and where the benefits of asynchronously * where data updates are rapid-fire and unpredictable, and where the benefits of asynchronously
* diffing the adapter outweigh the shortcomings. * diffing the adapter outweigh the shortcomings.
* @author OxygenCobalt
*/ */
class AsyncBackingData<T>( class AsyncBackingData<T>(
adapter: RecyclerView.Adapter<*>, adapter: RecyclerView.Adapter<*>,

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.playback package org.oxycblt.auxio.ui
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
@ -29,33 +29,33 @@ import org.oxycblt.auxio.util.getDimenSizeSafe
import org.oxycblt.auxio.util.getDrawableSafe import org.oxycblt.auxio.util.getDrawableSafe
/** /**
* An [AppCompatImageButton] designed for the buttons used in the playback display. * An [AppCompatImageButton] that applies many of the stylistic choices that Auxio uses regarding
* buttons.
* *
* Auxio's playback buttons have never followed the typical 24dp icon size that all other UI * More specifically, this class add two features:
* elements do, mostly because those icons just look bad at that size with all the gobs of * - Specification of the icon size. This is to accommodate the playback buttons, which tend to be
* whitespace surrounding them. So, this view resizes the icons to a fixed 32dp in a way that * larger as by default the playback icons look terrible with the gobs of whitespace everywhere.
* doesn't require a whole new icon set. * - Addition of an indicator, which is a dot that can denote when a button is active. This is
* * also useful for the playback buttons, as at times highlighting them is not enough to
* This view also enables use of an "indicator", which is a dot that can denote when a button is * differentiate them.
* active. This is useful for the shuffle/repeat buttons, as at times highlighting them is not * @author OxygenCobalt
* enough to differentiate them.
*/ */
class PlaybackButton class StyledImageButton
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
AppCompatImageButton(context, attrs, defStyleAttr) { AppCompatImageButton(context, attrs, defStyleAttr) {
private val iconSize = context.getDimenSizeSafe(R.dimen.size_playback_icon) private val iconSize: Int
private val centerMatrix = Matrix()
private val matrixSrc = RectF()
private val matrixDst = RectF()
private val indicatorDrawable = context.getDrawableSafe(R.drawable.ui_indicator)
private var hasIndicator = false private var hasIndicator = false
set(value) { set(value) {
field = value field = value
invalidate() invalidate()
} }
private val centerMatrix = Matrix()
private val matrixSrc = RectF()
private val matrixDst = RectF()
private val indicatorDrawable = context.getDrawableSafe(R.drawable.ui_indicator)
init { init {
val size = context.getDimenSizeSafe(R.dimen.size_btn_small) val size = context.getDimenSizeSafe(R.dimen.size_btn_small)
minimumWidth = size minimumWidth = size
@ -63,14 +63,22 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
scaleType = ScaleType.MATRIX scaleType = ScaleType.MATRIX
setBackgroundResource(R.drawable.ui_large_unbounded_ripple) setBackgroundResource(R.drawable.ui_large_unbounded_ripple)
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.PlaybackButton) val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageButton)
hasIndicator = styledAttrs.getBoolean(R.styleable.PlaybackButton_hasIndicator, false) iconSize =
styledAttrs
.getDimension(
R.styleable.StyledImageButton_iconSize,
context.getDimenSizeSafe(R.dimen.size_icon_normal).toFloat())
.toInt()
hasIndicator = styledAttrs.getBoolean(R.styleable.StyledImageButton_hasIndicator, false)
styledAttrs.recycle() styledAttrs.recycle()
} }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// TODO: Scale this drawable based on available space after padding
imageMatrix = imageMatrix =
centerMatrix.apply { centerMatrix.apply {
reset() reset()

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.ui
import android.content.Context
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView
import coil.dispose
import coil.load
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.SquareFrameTransform
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.getColorStateListSafe
import org.oxycblt.auxio.util.getDrawableSafe
/**
* 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) :
AppCompatImageView(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()
clipToOutline = true
background =
MaterialShapeDrawable().apply {
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(HalfSizeDrawable(drawable))
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// 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.
if (!isInEditMode) {
val settingsManager = SettingsManager.getInstance()
if (settingsManager.roundCovers) {
(background as MaterialShapeDrawable).setCornerSize(cornerRadius)
}
}
}
/** Bind the album cover for a [song]. */
fun bind(song: Song) = load(song, R.drawable.ic_song, R.string.desc_album_cover)
/** Bind the album cover for an [album]. */
fun bind(album: Album) = load(album, R.drawable.ic_album, R.string.desc_album_cover)
/** Bind the image for an [artist] */
fun bind(artist: Artist) = load(artist, R.drawable.ic_artist, R.string.desc_artist_image)
/** Bind the image for a [genre] */
fun bind(genre: Genre) = load(genre, R.drawable.ic_genre, R.string.desc_genre_image)
private fun <T : Music> load(music: T, @DrawableRes error: Int, @StringRes desc: Int) {
dispose()
load(music) {
error(HalfSizeDrawable(context, error))
transformations(SquareFrameTransform.INSTANCE)
}
contentDescription = context.getString(desc, music.resolveName(context))
}
private class HalfSizeDrawable(private val src: Drawable) : Drawable() {
constructor(context: Context, @DrawableRes res: Int) : this(context.getDrawableSafe(res))
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

@ -28,6 +28,10 @@ import androidx.viewbinding.ViewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
/**
* A dialog fragment enabling ViewBinding inflation and usage across the dialog fragment lifecycle.
* @author OxygenCobalt
*/
abstract class ViewBindingDialogFragment<T : ViewBinding> : DialogFragment() { abstract class ViewBindingDialogFragment<T : ViewBinding> : DialogFragment() {
private var _binding: T? = null private var _binding: T? = null

View file

@ -25,7 +25,10 @@ import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
/** A fragment enabling ViewBinding inflation and usage across the fragment lifecycle. */ /**
* A fragment enabling ViewBinding inflation and usage across the fragment lifecycle.
* @author OxygenCobalt
*/
abstract class ViewBindingFragment<T : ViewBinding> : Fragment() { abstract class ViewBindingFragment<T : ViewBinding> : Fragment() {
private var _binding: T? = null private var _binding: T? = null

View file

@ -20,9 +20,6 @@ package org.oxycblt.auxio.ui
import android.content.Context import android.content.Context
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.coil.bindAlbumCover
import org.oxycblt.auxio.coil.bindArtistImage
import org.oxycblt.auxio.coil.bindGenreImage
import org.oxycblt.auxio.databinding.ItemHeaderBinding import org.oxycblt.auxio.databinding.ItemHeaderBinding
import org.oxycblt.auxio.databinding.ItemParentBinding import org.oxycblt.auxio.databinding.ItemParentBinding
import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.databinding.ItemSongBinding
@ -35,11 +32,14 @@ import org.oxycblt.auxio.util.getPluralSafe
import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.textSafe import org.oxycblt.auxio.util.textSafe
/** The shared ViewHolder for a [Song]. */ /**
* The shared ViewHolder for a [Song].
* @author OxygenCobalt
*/
class SongViewHolder private constructor(private val binding: ItemSongBinding) : class SongViewHolder private constructor(private val binding: ItemSongBinding) :
BindingViewHolder<Song, MenuItemListener>(binding.root) { BindingViewHolder<Song, MenuItemListener>(binding.root) {
override fun bind(item: Song, listener: MenuItemListener) { override fun bind(item: Song, listener: MenuItemListener) {
binding.songAlbumCover.bindAlbumCover(item) binding.songAlbumCover.bind(item)
binding.songName.textSafe = item.resolveName(binding.context) binding.songName.textSafe = item.resolveName(binding.context)
binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context)
binding.root.apply { binding.root.apply {
@ -70,14 +70,17 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) :
} }
} }
/** The Shared ViewHolder for a [Album]. */ /**
* The Shared ViewHolder for a [Album].
* @author OxygenCobalt
*/
class AlbumViewHolder class AlbumViewHolder
private constructor( private constructor(
private val binding: ItemParentBinding, private val binding: ItemParentBinding,
) : BindingViewHolder<Album, MenuItemListener>(binding.root) { ) : BindingViewHolder<Album, MenuItemListener>(binding.root) {
override fun bind(item: Album, listener: MenuItemListener) { override fun bind(item: Album, listener: MenuItemListener) {
binding.parentImage.bindAlbumCover(item) binding.parentImage.bind(item)
binding.parentName.textSafe = item.resolveName(binding.context) binding.parentName.textSafe = item.resolveName(binding.context)
binding.parentInfo.textSafe = item.artist.resolveName(binding.context) binding.parentInfo.textSafe = item.artist.resolveName(binding.context)
binding.root.apply { binding.root.apply {
@ -108,12 +111,15 @@ private constructor(
} }
} }
/** The Shared ViewHolder for a [Artist]. */ /**
* The Shared ViewHolder for a [Artist].
* @author OxygenCobalt
*/
class ArtistViewHolder private constructor(private val binding: ItemParentBinding) : class ArtistViewHolder private constructor(private val binding: ItemParentBinding) :
BindingViewHolder<Artist, MenuItemListener>(binding.root) { BindingViewHolder<Artist, MenuItemListener>(binding.root) {
override fun bind(item: Artist, listener: MenuItemListener) { override fun bind(item: Artist, listener: MenuItemListener) {
binding.parentImage.bindArtistImage(item) binding.parentImage.bind(item)
binding.parentName.textSafe = item.resolveName(binding.context) binding.parentName.textSafe = item.resolveName(binding.context)
binding.parentInfo.textSafe = binding.parentInfo.textSafe =
binding.context.getString( binding.context.getString(
@ -149,14 +155,17 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin
} }
} }
/** The Shared ViewHolder for a [Genre]. */ /**
* The Shared ViewHolder for a [Genre].
* @author OxygenCobalt
*/
class GenreViewHolder class GenreViewHolder
private constructor( private constructor(
private val binding: ItemParentBinding, private val binding: ItemParentBinding,
) : BindingViewHolder<Genre, MenuItemListener>(binding.root) { ) : BindingViewHolder<Genre, MenuItemListener>(binding.root) {
override fun bind(item: Genre, listener: MenuItemListener) { override fun bind(item: Genre, listener: MenuItemListener) {
binding.parentImage.bindGenreImage(item) binding.parentImage.bind(item)
binding.parentName.textSafe = item.resolveName(binding.context) binding.parentName.textSafe = item.resolveName(binding.context)
binding.parentInfo.textSafe = binding.parentInfo.textSafe =
binding.context.getPluralSafe(R.plurals.fmt_song_count, item.songs.size) binding.context.getPluralSafe(R.plurals.fmt_song_count, item.songs.size)
@ -187,7 +196,10 @@ private constructor(
} }
} }
/** The Shared ViewHolder for a [Header]. */ /**
* The Shared ViewHolder for a [Header].
* @author OxygenCobalt
*/
class NewHeaderViewHolder private constructor(private val binding: ItemHeaderBinding) : class NewHeaderViewHolder private constructor(private val binding: ItemHeaderBinding) :
BindingViewHolder<Header, Unit>(binding.root) { BindingViewHolder<Header, Unit>(binding.root) {

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.accent package org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.R import org.oxycblt.auxio.R

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.accent package org.oxycblt.auxio.ui.accent
import android.content.Context import android.content.Context
import androidx.appcompat.widget.TooltipCompat import androidx.appcompat.widget.TooltipCompat

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.accent package org.oxycblt.auxio.ui.accent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater

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.accent package org.oxycblt.auxio.ui.accent
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet

View file

@ -26,8 +26,6 @@ import org.oxycblt.auxio.playback.system.PlaybackService
import org.oxycblt.auxio.util.newBroadcastIntent import org.oxycblt.auxio.util.newBroadcastIntent
import org.oxycblt.auxio.util.newMainIntent import org.oxycblt.auxio.util.newMainIntent
// TODO: Still need to change the default cover here
/** /**
* The default widget is displayed whenever there is no music playing. It just shows the message "No * The default widget is displayed whenever there is no music playing. It just shows the message "No
* music playing". * music playing".
@ -109,7 +107,7 @@ private fun RemoteViews.applyCover(
R.id.widget_cover, R.id.widget_cover,
context.getString(R.string.desc_album_cover, state.song.album.resolveName(context))) context.getString(R.string.desc_album_cover, state.song.album.resolveName(context)))
} else { } else {
setImageViewResource(R.id.widget_cover, R.drawable.ic_widget_album) setImageViewResource(R.id.widget_cover, R.drawable.ic_remote_default_cover)
setContentDescription(R.id.widget_cover, context.getString(R.string.desc_no_cover)) setContentDescription(R.id.widget_cover, context.getString(R.string.desc_no_cover))
} }

View file

@ -24,8 +24,8 @@ import coil.request.ImageRequest
import coil.size.Size import coil.size.Size
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import kotlin.math.min import kotlin.math.min
import org.oxycblt.auxio.coil.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.coil.SquareFrameTransform import org.oxycblt.auxio.image.SquareFrameTransform
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.PlaybackStateManager
@ -87,7 +87,7 @@ class WidgetComponent(private val context: Context) :
val metrics = context.resources.displayMetrics val metrics = context.resources.displayMetrics
// Use RoundedCornersTransformation. This is because our hack to get a 1:1 // Use RoundedCornersTransformation. This is because our hack to get a 1:1
// aspect ratio on widget ImageViews doesn't actually result in a square // aspect ratio on widget ImageViews doesn't actually result in a square
// ImageView, so clipToOutline won't work. // ImageView, so clipToOutline won't work.
builder builder
.transformations( .transformations(

View file

@ -6,11 +6,11 @@
android:viewportHeight="24"> android:viewportHeight="24">
<!-- <!--
Special album icon where the center is filled with the surface color. Special album icon where the center is filled with the surface color.
This is used for widgets specifically, as it creates a contiguous surface
that looks nicer on the small widgets while also lining up with the preview.
This does cause issues when the theme is changed on older android versions, but We would normally use a song icon with a filled-in background, but RemoteView
this is tolerable. limitations make that effectively impossible. Once again, the widget has to
be inconsistent with the rest of the app because google refuses to dumpster
a terrible API.
--> -->
<path <path
android:fillColor="?attr/colorPrimary" android:fillColor="?attr/colorPrimary"

View file

@ -6,7 +6,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -117,7 +117,7 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -125,16 +125,18 @@
android:contentDescription="@string/desc_change_repeat" android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat" android:src="@drawable/ic_repeat"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_prev" android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_repeat" app:layout_constraintStart_toEndOf="@+id/playback_repeat"
@ -153,24 +155,26 @@
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar" app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
tools:src="@drawable/ic_play" /> tools:src="@drawable/ic_play" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_next" android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle" app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
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.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium" android:layout_marginEnd="@dimen/spacing_medium"
android:contentDescription="@string/desc_shuffle" android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle" android:src="@drawable/ic_shuffle"
app:iconSize="@dimen/size_icon_large"
app:hasIndicator="true" app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -6,7 +6,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -115,7 +115,7 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -123,18 +123,20 @@
android:contentDescription="@string/desc_change_repeat" android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat" android:src="@drawable/ic_repeat"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev" app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_large" android:layout_marginEnd="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_prev" android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
@ -152,18 +154,19 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:src="@drawable/ic_pause" /> tools:src="@drawable/ic_pause" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large" android:layout_marginStart="@dimen/spacing_large"
android:contentDescription="@string/desc_skip_next" android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
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.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -171,6 +174,7 @@
android:contentDescription="@string/desc_shuffle" android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle" android:src="@drawable/ic_shuffle"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next" app:layout_constraintStart_toEndOf="@+id/playback_skip_next"
app:layout_constraintTop_toTopOf="@+id/playback_skip_next" app:layout_constraintTop_toTopOf="@+id/playback_skip_next"

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -104,26 +104,28 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_mid_large" android:layout_marginEnd="@dimen/spacing_mid_large"
android:contentDescription="@string/desc_change_repeat" android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat" android:src="@drawable/ic_repeat"
app:iconSize="@dimen/size_icon_large"
app:hasIndicator="true" app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev" app:layout_constraintEnd_toStartOf="@+id/playback_skip_prev"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_mid_large" android:layout_marginEnd="@dimen/spacing_mid_large"
android:contentDescription="@string/desc_skip_prev" android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
@ -141,18 +143,19 @@
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar" app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
tools:src="@drawable/ic_pause" /> tools:src="@drawable/ic_pause" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large" android:layout_marginStart="@dimen/spacing_mid_large"
android:contentDescription="@string/desc_skip_next" android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
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.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -160,6 +163,7 @@
android:contentDescription="@string/desc_shuffle" android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle" android:src="@drawable/ic_shuffle"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintStart_toEndOf="@+id/playback_skip_next" app:layout_constraintStart_toEndOf="@+id/playback_skip_next"
app:layout_constraintTop_toTopOf="@+id/playback_skip_next" app:layout_constraintTop_toTopOf="@+id/playback_skip_next"

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

View file

@ -6,14 +6,14 @@
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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar" app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
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:icon="@drawable/ic_song" />
<TextView <TextView
android:id="@+id/playback_song" android:id="@+id/playback_song"
@ -44,39 +44,42 @@
app:layout_constraintTop_toBottomOf="@+id/playback_song" app:layout_constraintTop_toBottomOf="@+id/playback_song"
tools:text="Artist Name / Album Name" /> tools:text="Artist Name / Album Name" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_song" app:layout_constraintStart_toEndOf="@+id/playback_song"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_play_pause" android:id="@+id/playback_play_pause"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/sel_playing_state" android:src="@drawable/sel_playing_state"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar" app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_next" app:layout_constraintEnd_toStartOf="@+id/playback_skip_next"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_skip_prev" app:layout_constraintStart_toEndOf="@+id/playback_skip_prev"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"

View file

@ -6,7 +6,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -117,7 +117,7 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -125,17 +125,19 @@
android:contentDescription="@string/desc_change_repeat" android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat" android:src="@drawable/ic_repeat"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar" app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_prev" android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_repeat" app:layout_constraintStart_toEndOf="@+id/playback_repeat"
@ -155,24 +157,26 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:src="@drawable/ic_pause" /> tools:src="@drawable/ic_pause" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_next" android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle" app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
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.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_medium" android:layout_marginEnd="@dimen/spacing_medium"
android:contentDescription="@string/desc_shuffle" android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle" android:src="@drawable/ic_shuffle"
app:iconSize="@dimen/size_icon_large"
app:hasIndicator="true" app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar" app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"

View file

@ -6,14 +6,14 @@
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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar" app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
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:icon="@drawable/ic_song" />
<TextView <TextView
android:id="@+id/playback_song" android:id="@+id/playback_song"
@ -42,39 +42,42 @@
app:layout_constraintTop_toBottomOf="@+id/playback_song" app:layout_constraintTop_toBottomOf="@+id/playback_song"
tools:text="Artist Name / Album Name" /> tools:text="Artist Name / Album Name" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_song" app:layout_constraintStart_toEndOf="@+id/playback_song"
app:layout_constraintTop_toTopOf="@+id/playback_play_pause" /> app:layout_constraintTop_toTopOf="@+id/playback_play_pause" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_play_pause" android:id="@+id/playback_play_pause"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/sel_playing_state" android:src="@drawable/sel_playing_state"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar" app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintEnd_toStartOf="@+id/playback_skip_next" app:layout_constraintEnd_toStartOf="@+id/playback_skip_next"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_skip_prev" app:layout_constraintStart_toEndOf="@+id/playback_skip_prev"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/playback_play_pause" app:layout_constraintStart_toEndOf="@+id/playback_play_pause"

View file

@ -10,7 +10,7 @@
android:paddingTop="@dimen/spacing_medium" android:paddingTop="@dimen/spacing_medium"
android:paddingEnd="@dimen/spacing_medium" android:paddingEnd="@dimen/spacing_medium"
android:paddingBottom="@dimen/spacing_small" android:paddingBottom="@dimen/spacing_small"
app:layoutManager="org.oxycblt.auxio.accent.AccentGridLayoutManager" app:layoutManager=".ui.accent.AccentGridLayoutManager"
app:layout_constraintBottom_toTopOf="@+id/accent_cancel" app:layout_constraintBottom_toTopOf="@+id/accent_cancel"
app:layout_constraintTop_toBottomOf="@+id/accent_header" app:layout_constraintTop_toBottomOf="@+id/accent_header"
tools:itemCount="18" tools:itemCount="18"

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -43,13 +43,14 @@
app:layout_constraintTop_toBottomOf="@+id/playback_song" app:layout_constraintTop_toBottomOf="@+id/playback_song"
tools:text="Artist Name / Album Name" /> tools:text="Artist Name / Album Name" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_play_pause" android:id="@+id/playback_play_pause"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small" android:layout_margin="@dimen/spacing_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/sel_playing_state" android:src="@drawable/sel_playing_state"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar" app:layout_constraintBottom_toTopOf="@+id/playback_progress_bar"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />

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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
@ -101,7 +101,7 @@
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:text="16:16" /> tools:text="16:16" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_repeat" android:id="@+id/playback_repeat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -109,16 +109,18 @@
android:contentDescription="@string/desc_change_repeat" android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat" android:src="@drawable/ic_repeat"
app:hasIndicator="true" app:hasIndicator="true"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_prev"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" /> app:layout_constraintTop_toTopOf="@+id/playback_skip_prev" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_prev" android:id="@+id/playback_skip_prev"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_prev" android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" android:src="@drawable/ic_skip_prev"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_play_pause" app:layout_constraintEnd_toStartOf="@+id/playback_play_pause"
app:layout_constraintStart_toEndOf="@+id/playback_repeat" app:layout_constraintStart_toEndOf="@+id/playback_repeat"
@ -137,7 +139,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
tools:src="@drawable/ic_play" /> tools:src="@drawable/ic_play" />
<org.oxycblt.auxio.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_skip_next" android:id="@+id/playback_skip_next"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -145,12 +147,13 @@
android:minWidth="@dimen/size_btn_small" android:minWidth="@dimen/size_btn_small"
android:minHeight="@dimen/size_btn_small" android:minHeight="@dimen/size_btn_small"
android:src="@drawable/ic_skip_next" android:src="@drawable/ic_skip_next"
app:iconSize="@dimen/size_icon_large"
app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause" app:layout_constraintBottom_toBottomOf="@+id/playback_play_pause"
app:layout_constraintEnd_toStartOf="@+id/playback_shuffle" app:layout_constraintEnd_toStartOf="@+id/playback_shuffle"
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.playback.PlaybackButton <org.oxycblt.auxio.ui.StyledImageButton
android:id="@+id/playback_shuffle" android:id="@+id/playback_shuffle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -159,6 +162,7 @@
android:minWidth="@dimen/size_btn_small" android:minWidth="@dimen/size_btn_small"
android:minHeight="@dimen/size_btn_small" android:minHeight="@dimen/size_btn_small"
android:src="@drawable/ic_shuffle" android:src="@drawable/ic_shuffle"
app:iconSize="@dimen/size_icon_large"
app:hasIndicator="true" app:hasIndicator="true"
app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next" app:layout_constraintBottom_toBottomOf="@+id/playback_skip_next"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -10,7 +10,7 @@
to be alike to other songs. So, add a pastel-ish background to each track number to be alike to other songs. So, add a pastel-ish background to each track number
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.coil.StyledImageView <org.oxycblt.auxio.ui.StyledImageView
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:src="@drawable/ic_song" android:src="@drawable/ic_song"

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:app="http://schemas.android.com/apk/res-auto"
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.coil.StyledImageView <org.oxycblt.auxio.ui.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"

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="@dimen/spacing_medium"> android:padding="@dimen/spacing_medium">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

View file

@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

View file

@ -4,7 +4,7 @@
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.coil.StyledImageView <org.oxycblt.auxio.ui.StyledImageView
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"

View file

@ -27,7 +27,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/colorSurface"> android:background="?attr/colorSurface">
<org.oxycblt.auxio.coil.StyledImageView <org.oxycblt.auxio.ui.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"

View file

@ -4,7 +4,7 @@
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.coil.StyledImageView <org.oxycblt.auxio.ui.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"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View file

@ -43,7 +43,7 @@
android:layout_alignTop="@id/widget_aspect_ratio" android:layout_alignTop="@id/widget_aspect_ratio"
android:layout_alignEnd="@id/widget_aspect_ratio" android:layout_alignEnd="@id/widget_aspect_ratio"
android:layout_alignBottom="@id/widget_aspect_ratio" android:layout_alignBottom="@id/widget_aspect_ratio"
android:src="@drawable/ic_widget_album" android:src="@drawable/ic_remote_default_cover"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<android.widget.LinearLayout <android.widget.LinearLayout

View file

@ -43,7 +43,7 @@
android:layout_alignTop="@id/widget_aspect_ratio" android:layout_alignTop="@id/widget_aspect_ratio"
android:layout_alignEnd="@id/widget_aspect_ratio" android:layout_alignEnd="@id/widget_aspect_ratio"
android:layout_alignBottom="@id/widget_aspect_ratio" android:layout_alignBottom="@id/widget_aspect_ratio"
android:src="@drawable/ic_widget_album" android:src="@drawable/ic_remote_default_cover"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<android.widget.LinearLayout <android.widget.LinearLayout

View file

@ -45,7 +45,7 @@
android:layout_alignTop="@id/widget_aspect_ratio" android:layout_alignTop="@id/widget_aspect_ratio"
android:layout_alignEnd="@id/widget_aspect_ratio" android:layout_alignEnd="@id/widget_aspect_ratio"
android:layout_alignBottom="@id/widget_aspect_ratio" android:layout_alignBottom="@id/widget_aspect_ratio"
android:src="@drawable/ic_widget_album" android:src="@drawable/ic_remote_default_cover"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<android.widget.LinearLayout <android.widget.LinearLayout

View file

@ -26,7 +26,7 @@
android:layout_marginEnd="@dimen/spacing_medium" android:layout_marginEnd="@dimen/spacing_medium"
android:contentDescription="@string/desc_no_cover" android:contentDescription="@string/desc_no_cover"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:src="@drawable/ic_widget_album" /> android:src="@drawable/ic_remote_default_cover" />
<android.widget.LinearLayout <android.widget.LinearLayout
android:layout_width="0dp" android:layout_width="0dp"

View file

@ -45,7 +45,7 @@
android:layout_alignTop="@id/widget_aspect_ratio" android:layout_alignTop="@id/widget_aspect_ratio"
android:layout_alignEnd="@id/widget_aspect_ratio" android:layout_alignEnd="@id/widget_aspect_ratio"
android:layout_alignBottom="@id/widget_aspect_ratio" android:layout_alignBottom="@id/widget_aspect_ratio"
android:src="@drawable/ic_widget_album" android:src="@drawable/ic_remote_default_cover"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<android.widget.LinearLayout <android.widget.LinearLayout

View file

@ -4,7 +4,8 @@
<attr name="cornerRadius" format="dimension" /> <attr name="cornerRadius" format="dimension" />
</declare-styleable> </declare-styleable>
<declare-styleable name="PlaybackButton"> <declare-styleable name="StyledImageButton">
<attr name="iconSize" format="dimension" />
<attr name="hasIndicator" format="boolean" /> <attr name="hasIndicator" format="boolean" />
</declare-styleable> </declare-styleable>

View file

@ -21,7 +21,8 @@
<dimen name="size_corners_small">8dp</dimen> <dimen name="size_corners_small">8dp</dimen>
<dimen name="size_corners_large">16dp</dimen> <dimen name="size_corners_large">16dp</dimen>
<dimen name="size_playback_icon">32dp</dimen> <dimen name="size_icon_normal">24dp</dimen>
<dimen name="size_icon_large">32dp</dimen>
<dimen name="text_size_ext_label_larger">16sp</dimen> <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_large">18sp</dimen>

View file

@ -174,7 +174,7 @@
--> -->
<item name="fabSize">normal</item> <item name="fabSize">normal</item>
<item name="fabCustomSize">@dimen/size_btn_large</item> <item name="fabCustomSize">@dimen/size_btn_large</item>
<item name="maxImageSize">@dimen/size_playback_icon</item> <item name="maxImageSize">@dimen/size_icon_large</item>
<item name="android:elevation">0dp</item> <item name="android:elevation">0dp</item>
<item name="elevation">0dp</item> <item name="elevation">0dp</item>
</style> </style>