diff --git a/CHANGELOG.md b/CHANGELOG.md index ffa6d36dd..b849d1f83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - Genre parsing now handles multiple integer values and cover/remix indicators (May wipe playback state) - "Rounded album covers" option is no longer dependent on "Show album covers" option - Added song actions to the playback panel +- Playback controls are now easier to reach when gesture navigation is enabled #### What's Fixed - Playback bar now picks the larger inset in case that gesture inset is missing [#149] diff --git a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt index e6186b74b..5a9cb2215 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt @@ -20,7 +20,6 @@ package org.oxycblt.auxio.detail import android.os.Bundle import android.text.format.Formatter import android.view.LayoutInflater -import android.webkit.MimeTypeMap import androidx.appcompat.app.AlertDialog import androidx.core.view.isGone import androidx.fragment.app.activityViewModels @@ -34,7 +33,6 @@ import org.oxycblt.auxio.util.launch class SongDetailDialog : ViewBindingDialogFragment() { private val detailModel: DetailViewModel by activityViewModels() - private val mimeTypes = MimeTypeMap.getSingleton() override fun onCreateBinding(inflater: LayoutInflater) = DialogSongDetailBinding.inflate(inflater) @@ -83,41 +81,6 @@ class SongDetailDialog : ViewBindingDialogFragment() { } } - private fun getMimeName(mime: String): String? { - return when (mime) { - // Since Auxio only feasibly loads music, we can match for general mime types - // and assume that they are audio-based. - - // Classic formats - "audio/mpeg", - "audio/mp3" -> "MPEG-1 Layer 3" - "audio/ogg", - "application/ogg" -> "OGG" - "audio/vorbis" -> "OGG Vorbis" - "audio/opus" -> "OGG Opus" - "audio/flac" -> "(OGG) FLAC" - - // Modern formats - "audio/mp4", - "audio/mp4a-latm", - "audio/mpeg4-generic", - "audio/aac", - "audio/3gpp", - "audio/3gpp2", -> "Advanced Audio Coding (AAC)" - "audio/x-matroska" -> "Matroska Audio (MKA)" - - // Windows formats - "audio/wav", - "audio/x-wav", - "audio/wave", - "audio/vnd.wave" -> "Microsoft WAV" - "audio/x-ms-wma" -> "Windows Media Audio (WMA)" - - // Don't know, fall back to an extension - else -> mimeTypes.getExtensionFromMimeType(mime)?.uppercase() - } - } - companion object { fun from(song: Song): SongDetailDialog { val instance = SongDetailDialog() diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 1dadf3ad8..70e9e7dae 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -89,15 +89,15 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI } binding.homeAppbar.apply { - addOnOffsetChangedListener( - AppBarLayout.OnOffsetChangedListener { _, offset -> - val range = binding.homeAppbar.totalScrollRange + addOnOffsetChangedListener { _, offset -> + val range = binding.homeAppbar.totalScrollRange - binding.homeToolbar.alpha = 1f - (abs(offset.toFloat()) / (range.toFloat() / 2)) + binding.homeToolbar.alpha = 1f - (abs(offset.toFloat()) / (range.toFloat() / 2)) - binding.homeContent.updatePadding( - bottom = binding.homeAppbar.totalScrollRange + offset) - }) + binding.homeContent.updatePadding( + bottom = binding.homeAppbar.totalScrollRange + offset + ) + } } binding.homeToolbar.apply { diff --git a/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt b/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt index 743bdcf55..45fb81e8d 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.music import android.content.Context import android.webkit.MimeTypeMap +import com.google.android.exoplayer2.util.MimeTypes import org.oxycblt.auxio.R /** @@ -74,51 +75,33 @@ sealed class Dir { */ data class MimeType(val fromExtension: String, val fromFormat: String?) { fun resolveName(context: Context): String { - // Prefer the format mime type first, as it actually is derived from the file - // and not the extension. Just make sure to ignore audio/raw, as that could feasibly - // correspond to multiple formats. - val readableMime = - if (fromFormat != null && fromFormat != "audio/raw") { - fromFormat - } else { - fromExtension - } - - // We have special names for the most common formats. + // While it would be nice to have more refined mime type names (Layer I/II/III, containers, + // etc.), it's not exactly practical with ExoPlayer. So, we go for the next best thing + // and try to find a good enough readable name to use. val readableStringRes = - when (readableMime) { - // MPEG formats - // While MP4 is AAC, it's considered separate given how common it is. - "audio/mpeg", - "audio/mp3" -> R.string.cdc_mp3 - "audio/mp4", - "audio/mp4a-latm", - "audio/mpeg4-generic" -> R.string.cdc_mp4 - - // Free formats - // Generic Ogg is included here as it's actually formatted as "Ogg", not "OGG" - "audio/ogg", - "application/ogg" -> R.string.cdc_ogg - "audio/vorbis" -> R.string.cdc_ogg_vorbis - "audio/opus" -> R.string.cdc_ogg_opus - "audio/flac" -> R.string.cdc_flac - - // The other AAC containers have a generic name - "audio/aac", - "audio/aacp", - "audio/aac-adts", - "audio/3gpp", - "audio/3gpp2", -> R.string.cdc_aac - - // Windows formats - "audio/wav", - "audio/x-wav", - "audio/wave", - "audio/vnd.wave" -> R.string.cdc_wav - "audio/x-ms-wma" -> R.string.cdc_wma - - // Don't know - else -> -1 + if (fromFormat != null && fromFormat != MimeTypes.AUDIO_RAW) { + // Prefer the extracted mime type, as it properly handles container formats and + // is agnostic to the file extension + when (fromFormat) { + MimeTypes.AUDIO_MPEG, + MimeTypes.AUDIO_MPEG_L1, + MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3 + MimeTypes.AUDIO_AAC -> R.string.cdc_mp4 + MimeTypes.AUDIO_VORBIS -> R.string.cdc_ogg_vorbis + MimeTypes.AUDIO_OPUS -> R.string.cdc_ogg_opus + MimeTypes.AUDIO_WAV -> R.string.cdc_wav + else -> -1 + } + } else { + // Fall back to the file extension in the case that we have a useless + when (fromExtension) { + "audio/mpeg" -> R.string.cdc_mp3 + "audio/mp4" -> R.string.cdc_mp4 + "audio/ogg" -> R.string.cdc_ogg + "audio/x-wav" -> R.string.cdc_wav + "audio/x-matroska" -> R.string.cdc_mka + else -> -1 + } } return if (readableStringRes > -1) { 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 2d1e54d07..6344fcbd5 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -24,6 +24,7 @@ import androidx.appcompat.widget.Toolbar import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import kotlin.math.max import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.detail.SongDetailDialog @@ -35,6 +36,7 @@ import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.util.getDrawableSafe import org.oxycblt.auxio.util.getSystemBarInsetsCompat +import org.oxycblt.auxio.util.getSystemGestureInsetsCompat import org.oxycblt.auxio.util.launch import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.textSafe @@ -67,8 +69,13 @@ class PlaybackPanelFragment : // --- UI SETUP --- binding.root.setOnApplyWindowInsetsListener { view, insets -> + // The playback controls should be inset upwards at least a little bit more than usual, + // just for quality of life. While the old 3-button navigation does this for us, when + // bar navigation is used, we use the gesture padding to add that extra portion of + // space. val bars = insets.getSystemBarInsetsCompat(view) - view.updatePadding(top = bars.top, bottom = bars.bottom) + val gestures = insets.getSystemGestureInsetsCompat(view) + view.updatePadding(top = bars.top, bottom = max(gestures.bottom, bars.bottom)) insets } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt index aeb9f6bef..05495b1a0 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt @@ -38,10 +38,7 @@ import org.oxycblt.auxio.util.logD * hot garbage. This shouldn't have *too many* UI bugs. I hope. * @author OxygenCobalt */ -class QueueDragCallback( - private val playbackModel: PlaybackViewModel, - private val queueAdapter: QueueAdapter -) : ItemTouchHelper.Callback() { +class QueueDragCallback(private val playbackModel: PlaybackViewModel) : ItemTouchHelper.Callback() { private var shouldLift = true override fun getMovementFlags( diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt index 3eeaffa47..045afb466 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt @@ -82,7 +82,7 @@ class QueueFragment : ViewBindingFragment(), QueueItemList if (instance != null) { return instance } - val newCallback = QueueDragCallback(playbackModel, queueAdapter) + val newCallback = QueueDragCallback(playbackModel) val newInstance = ItemTouchHelper(newCallback) callback = newCallback touchHelper = newInstance diff --git a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt index 5bc0db2b7..950ec46ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt @@ -131,28 +131,6 @@ fun Context.getAttrColorSafe(@AttrRes attr: Int): Int { return getColorSafe(color) } -/** - * Convenience method for getting a color attribute safely. - * @param attr The color attribute - * @return The attribute requested, or black if an error occurred. - */ -@ColorInt -fun Context.getAttrStateListSafe(@AttrRes attr: Int): ColorStateList { - // First resolve the attribute into its ID - val resolvedAttr = TypedValue() - theme.resolveAttribute(attr, resolvedAttr, true) - - // Then convert it to a proper color - val color = - if (resolvedAttr.resourceId != 0) { - resolvedAttr.resourceId - } else { - resolvedAttr.data - } - - return getColorStateListSafe(color) -} - /** * Convenience method for getting a [Drawable] safely. * @param drawable The drawable resource diff --git a/app/src/main/res/values-v23/styles_android.xml b/app/src/main/res/values-v23/styles_android.xml index ef59b3ceb..c8fa6b241 100644 --- a/app/src/main/res/values-v23/styles_android.xml +++ b/app/src/main/res/values-v23/styles_android.xml @@ -1,6 +1,6 @@ - + - +