From 2d7dbd19cd23e99ca73f3d8f500ba2f6c1b065ab Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sat, 21 May 2022 14:38:15 -0600 Subject: [PATCH] ui: rework custom ui components Refactor the package structure and implementation of custom UI components. --- CHANGELOG.md | 4 + .../main/java/org/oxycblt/auxio/AuxioApp.kt | 10 +- .../java/org/oxycblt/auxio/MainActivity.kt | 6 +- .../org/oxycblt/auxio/coil/StyledImageView.kt | 153 ------------------ .../detail/recycler/AlbumDetailAdapter.kt | 3 +- .../detail/recycler/ArtistDetailAdapter.kt | 8 +- .../detail/recycler/GenreDetailAdapter.kt | 6 +- .../auxio/{coil => image}/BaseFetcher.kt | 2 +- .../auxio/{coil => image}/BitmapProvider.kt | 2 +- .../auxio/{coil => image}/Components.kt | 2 +- .../auxio/{coil => image}/CrossfadeFactory.kt | 2 +- .../{coil => image}/SquareFrameTransform.kt | 2 +- .../auxio/playback/PlaybackBarFragment.kt | 3 +- .../auxio/playback/PlaybackPanelFragment.kt | 29 +--- .../auxio/playback/queue/QueueAdapter.kt | 3 +- .../playback/system/MediaSessionComponent.kt | 2 +- .../playback/system/NotificationComponent.kt | 2 +- .../oxycblt/auxio/settings/SettingsCompat.kt | 2 +- .../auxio/settings/SettingsListFragment.kt | 2 +- .../oxycblt/auxio/settings/SettingsManager.kt | 2 +- .../auxio/settings/pref/IntListPreference.kt | 3 +- .../auxio/settings/pref/M3SwitchPreference.kt | 3 +- .../java/org/oxycblt/auxio/ui/ActionMenu.kt | 4 +- .../oxycblt/auxio/ui/NavigationViewModel.kt | 5 +- .../org/oxycblt/auxio/ui/RecyclerFramework.kt | 5 + .../StyledImageButton.kt} | 46 +++--- .../org/oxycblt/auxio/ui/StyledImageView.kt | 140 ++++++++++++++++ .../auxio/ui/ViewBindingDialogFragment.kt | 4 + .../oxycblt/auxio/ui/ViewBindingFragment.kt | 5 +- .../java/org/oxycblt/auxio/ui/ViewHolders.kt | 36 +++-- .../oxycblt/auxio/{ => ui}/accent/Accent.kt | 2 +- .../auxio/{ => ui}/accent/AccentAdapter.kt | 2 +- .../{ => ui}/accent/AccentCustomizeDialog.kt | 2 +- .../accent/AccentGridLayoutManager.kt | 2 +- .../java/org/oxycblt/auxio/widgets/Forms.kt | 4 +- .../oxycblt/auxio/widgets/WidgetComponent.kt | 6 +- ..._album.xml => ic_remote_default_cover.xml} | 8 +- .../main/res/layout-h600dp/item_detail.xml | 2 +- .../layout-land/fragment_playback_panel.xml | 14 +- app/src/main/res/layout-land/item_detail.xml | 2 +- .../fragment_playback_panel.xml | 14 +- .../fragment_playback_panel.xml | 14 +- .../main/res/layout-sw600dp/item_detail.xml | 2 +- .../layout-sw640dp/fragment_playback_bar.xml | 13 +- .../main/res/layout-sw840dp/item_detail.xml | 2 +- .../fragment_playback_panel.xml | 14 +- .../layout-w600dp/fragment_playback_bar.xml | 13 +- app/src/main/res/layout/dialog_accent.xml | 2 +- .../main/res/layout/fragment_playback_bar.xml | 5 +- .../res/layout/fragment_playback_panel.xml | 14 +- app/src/main/res/layout/item_album_song.xml | 2 +- app/src/main/res/layout/item_artist.xml | 3 +- app/src/main/res/layout/item_detail.xml | 2 +- app/src/main/res/layout/item_disc_header.xml | 2 +- app/src/main/res/layout/item_parent.xml | 2 +- app/src/main/res/layout/item_queue_song.xml | 2 +- app/src/main/res/layout/item_song.xml | 2 +- app/src/main/res/layout/widget_large.xml | 2 +- app/src/main/res/layout/widget_medium.xml | 2 +- app/src/main/res/layout/widget_small.xml | 2 +- app/src/main/res/layout/widget_tiny.xml | 2 +- app/src/main/res/layout/widget_wide.xml | 2 +- app/src/main/res/values/attrs.xml | 3 +- app/src/main/res/values/dimens.xml | 3 +- app/src/main/res/values/styles_ui.xml | 2 +- 65 files changed, 342 insertions(+), 324 deletions(-) delete mode 100644 app/src/main/java/org/oxycblt/auxio/coil/StyledImageView.kt rename app/src/main/java/org/oxycblt/auxio/{coil => image}/BaseFetcher.kt (99%) rename app/src/main/java/org/oxycblt/auxio/{coil => image}/BitmapProvider.kt (98%) rename app/src/main/java/org/oxycblt/auxio/{coil => image}/Components.kt (99%) rename app/src/main/java/org/oxycblt/auxio/{coil => image}/CrossfadeFactory.kt (98%) rename app/src/main/java/org/oxycblt/auxio/{coil => image}/SquareFrameTransform.kt (98%) rename app/src/main/java/org/oxycblt/auxio/{playback/PlaybackButton.kt => ui/StyledImageButton.kt} (77%) create mode 100644 app/src/main/java/org/oxycblt/auxio/ui/StyledImageView.kt rename app/src/main/java/org/oxycblt/auxio/{ => ui}/accent/Accent.kt (99%) rename app/src/main/java/org/oxycblt/auxio/{ => ui}/accent/AccentAdapter.kt (99%) rename app/src/main/java/org/oxycblt/auxio/{ => ui}/accent/AccentCustomizeDialog.kt (98%) rename app/src/main/java/org/oxycblt/auxio/{ => ui}/accent/AccentGridLayoutManager.kt (98%) rename app/src/main/res/drawable/{ic_widget_album.xml => ic_remote_default_cover.xml} (83%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad5ecae61..1e37ad868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Added disc number support - 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 +- 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 - Fixed incorrect ellipsizing on song items diff --git a/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt b/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt index 4f96102ff..a28e0d47a 100644 --- a/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt +++ b/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt @@ -21,11 +21,11 @@ import android.app.Application import coil.ImageLoader import coil.ImageLoaderFactory import coil.request.CachePolicy -import org.oxycblt.auxio.coil.AlbumArtFetcher -import org.oxycblt.auxio.coil.ArtistImageFetcher -import org.oxycblt.auxio.coil.CrossfadeFactory -import org.oxycblt.auxio.coil.GenreImageFetcher -import org.oxycblt.auxio.coil.MusicKeyer +import org.oxycblt.auxio.image.AlbumArtFetcher +import org.oxycblt.auxio.image.ArtistImageFetcher +import org.oxycblt.auxio.image.CrossfadeFactory +import org.oxycblt.auxio.image.GenreImageFetcher +import org.oxycblt.auxio.image.MusicKeyer import org.oxycblt.auxio.settings.SettingsManager @Suppress("UNUSED") diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 6e7f8906f..dac057bdf 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -42,13 +42,11 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat * * 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: Rework padding ethos + * + * @author OxygenCobalt */ class MainActivity : AppCompatActivity() { private val playbackModel: PlaybackViewModel by viewModels() diff --git a/app/src/main/java/org/oxycblt/auxio/coil/StyledImageView.kt b/app/src/main/java/org/oxycblt/auxio/coil/StyledImageView.kt deleted file mode 100644 index 724f2589e..000000000 --- a/app/src/main/java/org/oxycblt/auxio/coil/StyledImageView.kt +++ /dev/null @@ -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 . - */ - -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 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 - }) - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt index 1042780c0..eb1860bd2 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt @@ -22,7 +22,6 @@ import androidx.core.view.isInvisible import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R -import org.oxycblt.auxio.coil.bindAlbumCover import org.oxycblt.auxio.databinding.ItemAlbumSongBinding import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemDiscHeaderBinding @@ -123,7 +122,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite BindingViewHolder(binding.root) { override fun bind(item: Album, listener: AlbumDetailAdapter.Listener) { - binding.detailCover.bindAlbumCover(item) + binding.detailCover.bind(item) binding.detailName.textSafe = item.resolveName(binding.context) binding.detailSubhead.apply { diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt index 1e895089e..07faf46cd 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt @@ -21,8 +21,6 @@ import android.content.Context import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R -import org.oxycblt.auxio.coil.bindAlbumCover -import org.oxycblt.auxio.coil.bindArtistImage import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemParentBinding import org.oxycblt.auxio.databinding.ItemSongBinding @@ -139,7 +137,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It BindingViewHolder(binding.root) { override fun bind(item: Artist, listener: DetailAdapter.Listener) { - binding.detailCover.bindArtistImage(item) + binding.detailCover.bind(item) binding.detailName.textSafe = item.resolveName(binding.context) // 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, ) : BindingViewHolder(binding.root), Highlightable { override fun bind(item: Album, listener: MenuItemListener) { - binding.parentImage.bindAlbumCover(item) + binding.parentImage.bind(item) binding.parentName.textSafe = item.resolveName(binding.context) binding.parentInfo.textSafe = if (item.year != null) { @@ -226,7 +224,7 @@ private constructor( private val binding: ItemSongBinding, ) : BindingViewHolder(binding.root), Highlightable { override fun bind(item: Song, listener: MenuItemListener) { - binding.songAlbumCover.bindAlbumCover(item) + binding.songAlbumCover.bind(item) binding.songName.textSafe = item.resolveName(binding.context) binding.songInfo.textSafe = item.album.resolveName(binding.context) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt index f9000854d..dc5e7ae4d 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/GenreDetailAdapter.kt @@ -21,8 +21,6 @@ import android.content.Context import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R -import org.oxycblt.auxio.coil.bindAlbumCover -import org.oxycblt.auxio.coil.bindGenreImage import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.music.Genre @@ -114,7 +112,7 @@ class GenreDetailAdapter(listener: Listener) : private class GenreDetailViewHolder private constructor(private val binding: ItemDetailBinding) : BindingViewHolder(binding.root) { override fun bind(item: Genre, listener: DetailAdapter.Listener) { - binding.detailCover.bindGenreImage(item) + binding.detailCover.bind(item) binding.detailName.textSafe = item.resolveName(binding.context) binding.detailSubhead.textSafe = 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) : BindingViewHolder(binding.root), Highlightable { override fun bind(item: Song, listener: MenuItemListener) { - binding.songAlbumCover.bindAlbumCover(item) + binding.songAlbumCover.bind(item) binding.songName.textSafe = item.resolveName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) binding.root.apply { diff --git a/app/src/main/java/org/oxycblt/auxio/coil/BaseFetcher.kt b/app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/coil/BaseFetcher.kt rename to app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt index 7370e59de..d7e465fc2 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/BaseFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.coil +package org.oxycblt.auxio.image import android.content.Context import android.graphics.Bitmap diff --git a/app/src/main/java/org/oxycblt/auxio/coil/BitmapProvider.kt b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/coil/BitmapProvider.kt rename to app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt index ec6b3fd04..52b794a74 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/BitmapProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.coil +package org.oxycblt.auxio.image import android.content.Context import android.graphics.Bitmap diff --git a/app/src/main/java/org/oxycblt/auxio/coil/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/Components.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/coil/Components.kt rename to app/src/main/java/org/oxycblt/auxio/image/Components.kt index d2c2e0da7..8d5e5613a 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/Components.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.coil +package org.oxycblt.auxio.image import android.content.Context import coil.ImageLoader diff --git a/app/src/main/java/org/oxycblt/auxio/coil/CrossfadeFactory.kt b/app/src/main/java/org/oxycblt/auxio/image/CrossfadeFactory.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/coil/CrossfadeFactory.kt rename to app/src/main/java/org/oxycblt/auxio/image/CrossfadeFactory.kt index a5b1e730c..6ba95cf93 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/CrossfadeFactory.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/CrossfadeFactory.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.coil +package org.oxycblt.auxio.image import coil.decode.DataSource import coil.drawable.CrossfadeDrawable diff --git a/app/src/main/java/org/oxycblt/auxio/coil/SquareFrameTransform.kt b/app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/coil/SquareFrameTransform.kt rename to app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt index 6895cc657..f81fd962f 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/SquareFrameTransform.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.coil +package org.oxycblt.auxio.image import android.graphics.Bitmap import coil.size.Size diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt index de58a4cc3..3de34434d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt @@ -25,7 +25,6 @@ import androidx.core.view.updatePadding import androidx.fragment.app.activityViewModels import com.google.android.material.color.MaterialColors import org.oxycblt.auxio.R -import org.oxycblt.auxio.coil.bindAlbumCover import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.MainNavigationAction @@ -104,7 +103,7 @@ class PlaybackBarFragment : ViewBindingFragment() { if (song != null) { val context = requireContext() val binding = requireBinding() - binding.playbackCover.bindAlbumCover(song) + binding.playbackCover.bind(song) binding.playbackSong.textSafe = song.resolveName(context) binding.playbackInfo.textSafe = song.resolveIndividualArtistName(context) binding.playbackProgressBar.max = song.durationSecs.toInt() diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt index d49a7f62c..fe2442370 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -28,7 +28,6 @@ import com.google.android.material.color.MaterialColors import com.google.android.material.slider.Slider import kotlin.math.max import org.oxycblt.auxio.R -import org.oxycblt.auxio.coil.bindAlbumCover import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song @@ -176,7 +175,7 @@ class PlaybackPanelFragment : val binding = requireBinding() val context = requireContext() - binding.playbackCover.bindAlbumCover(song) + binding.playbackCover.bind(song) binding.playbackSong.textSafe = song.resolveName(context) binding.playbackArtist.textSafe = song.resolveIndividualArtistName(context) binding.playbackAlbum.textSafe = song.album.resolveName(context) @@ -186,7 +185,7 @@ class PlaybackPanelFragment : binding.playbackDuration.textSafe = seconds.formatDuration(false) binding.playbackSeekBar.apply { isEnabled = seconds > 0L - valueToSafe = max(seconds, 1L).toFloat() + valueTo = max(seconds, 1L).toFloat() } } @@ -200,7 +199,7 @@ class PlaybackPanelFragment : // around. val binding = requireBinding() if (!binding.playbackPosition.isActivated) { - binding.playbackSeekBar.valueSafe = position.toFloat() + binding.playbackSeekBar.value = position.toFloat() binding.playbackPosition.textSafe = position.formatDuration(true) } } @@ -219,26 +218,4 @@ class PlaybackPanelFragment : private fun updateShuffled(isShuffled: Boolean) { 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 - } - } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index 3f22551fb..3f1d8738d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -28,7 +28,6 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.google.android.material.shape.MaterialShapeDrawable import org.oxycblt.auxio.IntegerTable -import org.oxycblt.auxio.coil.bindAlbumCover import org.oxycblt.auxio.databinding.ItemQueueSongBinding import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.ui.BackingData @@ -71,7 +70,7 @@ private constructor( @SuppressLint("ClickableViewAccessibility") override fun bind(item: Song, listener: QueueItemListener) { - binding.songAlbumCover.bindAlbumCover(item) + binding.songAlbumCover.bind(item) binding.songName.textSafe = item.resolveName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index b261391c9..a3a6098d6 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -25,7 +25,7 @@ import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat 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.Song import org.oxycblt.auxio.playback.state.PlaybackStateManager diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt index d75f8a8ac..15b9d16a4 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt @@ -30,7 +30,7 @@ import androidx.media.app.NotificationCompat.MediaStyle import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.IntegerTable 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.Song import org.oxycblt.auxio.playback.state.RepeatMode diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsCompat.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsCompat.kt index 7e13e07fe..5237729ef 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsCompat.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsCompat.kt @@ -19,7 +19,7 @@ package org.oxycblt.auxio.settings import android.content.SharedPreferences 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 diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index cde1cd4f8..3dc82fe04 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -30,12 +30,12 @@ import androidx.preference.children import androidx.recyclerview.widget.RecyclerView import coil.Coil import org.oxycblt.auxio.R -import org.oxycblt.auxio.accent.AccentCustomizeDialog import org.oxycblt.auxio.home.tabs.TabCustomizeDialog import org.oxycblt.auxio.music.excluded.ExcludedDialog import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.settings.pref.IntListPreference 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.isNight import org.oxycblt.auxio.util.logD diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt index cab931176..99815520d 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -22,12 +22,12 @@ import android.content.SharedPreferences import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit import androidx.preference.PreferenceManager -import org.oxycblt.auxio.accent.Accent import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.system.ReplayGainMode import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.Sort +import org.oxycblt.auxio.ui.accent.Accent import org.oxycblt.auxio.util.unlikelyToBeNull /** diff --git a/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPreference.kt index 8c1bc7b9e..778c5689a 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPreference.kt @@ -32,10 +32,11 @@ constructor( defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle, defStyleRes: Int = 0 ) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { - // Reflect into Preference to get the (normally inaccessible) default value. val entries: Array val values: IntArray private var currentValue: Int? = null + + // Reflect into Preference to get the (normally inaccessible) default value. private val defValue: Int get() = defValueField.get(this) as Int diff --git a/app/src/main/java/org/oxycblt/auxio/settings/pref/M3SwitchPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/pref/M3SwitchPreference.kt index d8170d753..49544b217 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/pref/M3SwitchPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/pref/M3SwitchPreference.kt @@ -29,7 +29,7 @@ import org.oxycblt.auxio.util.getDrawableSafe /** * 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 @JvmOverloads @@ -45,7 +45,6 @@ constructor( // Lollipop cannot into ColorStateList, disable this feature on that version if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val switch = holder.findViewById(androidx.preference.R.id.switchWidget) - if (switch is SwitchCompat) { switch.apply { trackDrawable = context.getDrawableSafe(R.drawable.ui_m3_switch_track) diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ActionMenu.kt b/app/src/main/java/org/oxycblt/auxio/ui/ActionMenu.kt index 77cd80115..df81099f8 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ActionMenu.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ActionMenu.kt @@ -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 * @author OxygenCobalt * - * TODO: Stop scrolling when a menu is open - * * TODO: Prevent duplicate menus from showing up * - * TODO: Maybe replace this with a bottom sheet? + * TODO: Add multi-select */ class ActionMenu( activity: AppCompatActivity, diff --git a/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt b/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt index 45a6ae47a..c42b62fb8 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt @@ -22,7 +22,10 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel 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() { private val _mainNavigationAction = MutableLiveData() /** Flag for main fragment navigation. Intended for MainFragment use only. */ diff --git a/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt b/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt index 5f1c15531..1c097ea7c 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/RecyclerFramework.kt @@ -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 * overridden values. + * @author OxygenCobalt */ abstract class MonoAdapter>(private val listener: L) : RecyclerView.Adapter() { @@ -51,6 +52,7 @@ private typealias AnyCreator = BindingViewHolder.Creator(private val listener: L) : RecyclerView.Adapter() { @@ -99,6 +101,7 @@ abstract class MultiAdapter(private val listener: L) : * 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 * entire adapter implementation for free. + * @author OxygenCobalt */ abstract class BindingViewHolder(root: View) : RecyclerView.ViewHolder(root) { abstract fun bind(item: T, listener: L) @@ -159,6 +162,7 @@ abstract class BackingData { /** * A list-backed [BackingData] that is modified using adapter primitives. Useful in cases where * [AsyncBackingData] is not preferable due to bugs involving diffing. + * @author OxygenCobalt */ class PrimitiveBackingData(private val adapter: RecyclerView.Adapter<*>) : BackingData() { private var _currentList = mutableListOf() @@ -184,6 +188,7 @@ class PrimitiveBackingData(private val adapter: RecyclerView.Adapter<*>) : Ba * 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 * diffing the adapter outweigh the shortcomings. + * @author OxygenCobalt */ class AsyncBackingData( adapter: RecyclerView.Adapter<*>, diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackButton.kt b/app/src/main/java/org/oxycblt/auxio/ui/StyledImageButton.kt similarity index 77% rename from app/src/main/java/org/oxycblt/auxio/playback/PlaybackButton.kt rename to app/src/main/java/org/oxycblt/auxio/ui/StyledImageButton.kt index ad44e5ca3..21b43815c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackButton.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/StyledImageButton.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback +package org.oxycblt.auxio.ui import android.content.Context import android.graphics.Canvas @@ -29,33 +29,33 @@ import org.oxycblt.auxio.util.getDimenSizeSafe 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 - * elements do, mostly because those icons just look bad at that size with all the gobs of - * whitespace surrounding them. So, this view resizes the icons to a fixed 32dp in a way that - * doesn't require a whole new icon set. - * - * This view also enables use of an "indicator", which is a dot that can denote when a button is - * active. This is useful for the shuffle/repeat buttons, as at times highlighting them is not - * enough to differentiate them. + * More specifically, this class add two features: + * - Specification of the icon size. This is to accommodate the playback buttons, which tend to be + * larger as by default the playback icons look terrible with the gobs of whitespace everywhere. + * - 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 + * differentiate them. + * @author OxygenCobalt */ -class PlaybackButton +class StyledImageButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : AppCompatImageButton(context, attrs, defStyleAttr) { - private val iconSize = context.getDimenSizeSafe(R.dimen.size_playback_icon) - private val centerMatrix = Matrix() - private val matrixSrc = RectF() - private val matrixDst = RectF() - - private val indicatorDrawable = context.getDrawableSafe(R.drawable.ui_indicator) + private val iconSize: Int private var hasIndicator = false set(value) { field = value invalidate() } + private val centerMatrix = Matrix() + private val matrixSrc = RectF() + private val matrixDst = RectF() + private val indicatorDrawable = context.getDrawableSafe(R.drawable.ui_indicator) + init { val size = context.getDimenSizeSafe(R.dimen.size_btn_small) minimumWidth = size @@ -63,14 +63,22 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr scaleType = ScaleType.MATRIX setBackgroundResource(R.drawable.ui_large_unbounded_ripple) - val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.PlaybackButton) - hasIndicator = styledAttrs.getBoolean(R.styleable.PlaybackButton_hasIndicator, false) + val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.StyledImageButton) + 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() } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) + // TODO: Scale this drawable based on available space after padding + imageMatrix = centerMatrix.apply { reset() diff --git a/app/src/main/java/org/oxycblt/auxio/ui/StyledImageView.kt b/app/src/main/java/org/oxycblt/auxio/ui/StyledImageView.kt new file mode 100644 index 000000000..e9b69c005 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/ui/StyledImageView.kt @@ -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 . + */ + +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 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 + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt index d54e3a53d..c5aff2564 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt @@ -28,6 +28,10 @@ import androidx.viewbinding.ViewBinding import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.oxycblt.auxio.util.logD +/** + * A dialog fragment enabling ViewBinding inflation and usage across the dialog fragment lifecycle. + * @author OxygenCobalt + */ abstract class ViewBindingDialogFragment : DialogFragment() { private var _binding: T? = null diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt index d2e932c3f..4497abac4 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt @@ -25,7 +25,10 @@ import androidx.fragment.app.Fragment import androidx.viewbinding.ViewBinding 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 : Fragment() { private var _binding: T? = null diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt index c93272e33..45fdbd121 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewHolders.kt @@ -20,9 +20,6 @@ package org.oxycblt.auxio.ui import android.content.Context import org.oxycblt.auxio.IntegerTable 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.ItemParentBinding 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.textSafe -/** The shared ViewHolder for a [Song]. */ +/** + * The shared ViewHolder for a [Song]. + * @author OxygenCobalt + */ class SongViewHolder private constructor(private val binding: ItemSongBinding) : BindingViewHolder(binding.root) { override fun bind(item: Song, listener: MenuItemListener) { - binding.songAlbumCover.bindAlbumCover(item) + binding.songAlbumCover.bind(item) binding.songName.textSafe = item.resolveName(binding.context) binding.songInfo.textSafe = item.resolveIndividualArtistName(binding.context) 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 private constructor( private val binding: ItemParentBinding, ) : BindingViewHolder(binding.root) { override fun bind(item: Album, listener: MenuItemListener) { - binding.parentImage.bindAlbumCover(item) + binding.parentImage.bind(item) binding.parentName.textSafe = item.resolveName(binding.context) binding.parentInfo.textSafe = item.artist.resolveName(binding.context) 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) : BindingViewHolder(binding.root) { override fun bind(item: Artist, listener: MenuItemListener) { - binding.parentImage.bindArtistImage(item) + binding.parentImage.bind(item) binding.parentName.textSafe = item.resolveName(binding.context) binding.parentInfo.textSafe = 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 private constructor( private val binding: ItemParentBinding, ) : BindingViewHolder(binding.root) { override fun bind(item: Genre, listener: MenuItemListener) { - binding.parentImage.bindGenreImage(item) + binding.parentImage.bind(item) binding.parentName.textSafe = item.resolveName(binding.context) binding.parentInfo.textSafe = 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) : BindingViewHolder(binding.root) { diff --git a/app/src/main/java/org/oxycblt/auxio/accent/Accent.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/accent/Accent.kt rename to app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt index 20ecf8149..3938b8745 100644 --- a/app/src/main/java/org/oxycblt/auxio/accent/Accent.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.accent +package org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.R diff --git a/app/src/main/java/org/oxycblt/auxio/accent/AccentAdapter.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/accent/AccentAdapter.kt rename to app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt index 0ae1b8ef3..0243fd0c9 100644 --- a/app/src/main/java/org/oxycblt/auxio/accent/AccentAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.accent +package org.oxycblt.auxio.ui.accent import android.content.Context import androidx.appcompat.widget.TooltipCompat diff --git a/app/src/main/java/org/oxycblt/auxio/accent/AccentCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/accent/AccentCustomizeDialog.kt rename to app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt index a384b580c..db945a60b 100644 --- a/app/src/main/java/org/oxycblt/auxio/accent/AccentCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.accent +package org.oxycblt.auxio.ui.accent import android.os.Bundle import android.view.LayoutInflater diff --git a/app/src/main/java/org/oxycblt/auxio/accent/AccentGridLayoutManager.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentGridLayoutManager.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/accent/AccentGridLayoutManager.kt rename to app/src/main/java/org/oxycblt/auxio/ui/accent/AccentGridLayoutManager.kt index ad9c91db0..2cb7b8cab 100644 --- a/app/src/main/java/org/oxycblt/auxio/accent/AccentGridLayoutManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentGridLayoutManager.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.accent +package org.oxycblt.auxio.ui.accent import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt index fc4b916a7..bf18449fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt @@ -26,8 +26,6 @@ import org.oxycblt.auxio.playback.system.PlaybackService import org.oxycblt.auxio.util.newBroadcastIntent 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 * music playing". @@ -109,7 +107,7 @@ private fun RemoteViews.applyCover( R.id.widget_cover, context.getString(R.string.desc_album_cover, state.song.album.resolveName(context))) } 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)) } diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index 5fd73c216..81be297fa 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -24,8 +24,8 @@ import coil.request.ImageRequest import coil.size.Size import coil.transform.RoundedCornersTransformation import kotlin.math.min -import org.oxycblt.auxio.coil.BitmapProvider -import org.oxycblt.auxio.coil.SquareFrameTransform +import org.oxycblt.auxio.image.BitmapProvider +import org.oxycblt.auxio.image.SquareFrameTransform import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.state.PlaybackStateManager @@ -87,7 +87,7 @@ class WidgetComponent(private val context: Context) : val metrics = context.resources.displayMetrics // 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. builder .transformations( diff --git a/app/src/main/res/drawable/ic_widget_album.xml b/app/src/main/res/drawable/ic_remote_default_cover.xml similarity index 83% rename from app/src/main/res/drawable/ic_widget_album.xml rename to app/src/main/res/drawable/ic_remote_default_cover.xml index 41ae54295..e29fbfca0 100644 --- a/app/src/main/res/drawable/ic_widget_album.xml +++ b/app/src/main/res/drawable/ic_remote_default_cover.xml @@ -6,11 +6,11 @@ android:viewportHeight="24"> - - - - - - - - - - @@ -152,18 +154,19 @@ app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar" tools:src="@drawable/ic_pause" /> - - - - - @@ -141,18 +143,19 @@ app:layout_constraintStart_toStartOf="@+id/playback_seek_bar" tools:src="@drawable/ic_pause" /> - - - - + tools:icon="@drawable/ic_song" /> - - - - - - - - - - + tools:icon="@drawable/ic_song" /> - - - - - diff --git a/app/src/main/res/layout/fragment_playback_panel.xml b/app/src/main/res/layout/fragment_playback_panel.xml index 389574ac6..1d5f3ccf6 100644 --- a/app/src/main/res/layout/fragment_playback_panel.xml +++ b/app/src/main/res/layout/fragment_playback_panel.xml @@ -14,7 +14,7 @@ app:title="@string/lbl_playback" tools:subtitle="@string/lbl_all_songs" /> - - - - - - - - - - - - - + android:src="@drawable/ic_remote_default_cover" /> - + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 28e7dd65b..baa70df53 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -21,7 +21,8 @@ 8dp 16dp - 32dp + 24dp + 32dp 16sp 18sp diff --git a/app/src/main/res/values/styles_ui.xml b/app/src/main/res/values/styles_ui.xml index b5d836d1f..b1f588657 100644 --- a/app/src/main/res/values/styles_ui.xml +++ b/app/src/main/res/values/styles_ui.xml @@ -174,7 +174,7 @@ --> normal @dimen/size_btn_large - @dimen/size_playback_icon + @dimen/size_icon_large 0dp 0dp