diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2e189db2d..8b0313ec5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,8 @@ + + + + + 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 70e9e7dae..9035c5d7c 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -34,7 +34,6 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator import kotlin.math.abs import org.oxycblt.auxio.R @@ -95,8 +94,7 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI binding.homeToolbar.alpha = 1f - (abs(offset.toFloat()) / (range.toFloat() / 2)) binding.homeContent.updatePadding( - bottom = binding.homeAppbar.totalScrollRange + offset - ) + bottom = binding.homeAppbar.totalScrollRange + offset) } } 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 45fb81e8d..3381e420f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/FileSystemFramework.kt @@ -75,37 +75,61 @@ sealed class Dir { */ data class MimeType(val fromExtension: String, val fromFormat: String?) { fun resolveName(context: Context): String { - // 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 = - 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 - } + // We try our best to produce a more readable name for the common audio formats. + val formatName = + when (fromFormat) { + // We start with the extracted mime types, as they are more consistent. Note that + // we do not include container formats at all with these names. It is only the + // inner codec that we show. + MimeTypes.AUDIO_MPEG, + MimeTypes.AUDIO_MPEG_L1, + MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3 + MimeTypes.AUDIO_AAC -> R.string.cdc_aac + MimeTypes.AUDIO_VORBIS -> R.string.cdc_vorbis + MimeTypes.AUDIO_OPUS -> R.string.cdc_opus + MimeTypes.AUDIO_FLAC -> R.string.cdc_flac + MimeTypes.AUDIO_WAV -> R.string.cdc_wav + + // We don't give a name to more unpopular formats. + + else -> -1 } - return if (readableStringRes > -1) { - context.getString(readableStringRes) + if (formatName > -1) { + return context.getString(formatName) + } + + // Fall back to the file extension in the case that we have no mime type or + // a useless "audio/raw" mime type. Here: + // - We return names for container formats instead of the inner format, as we + // cannot parse the file. + // - We are at the mercy of the Android OS, hence we check for every possible mime + // type for a particular format. + val extensionName = + when (fromExtension) { + "audio/mpeg", + "audio/mp3" -> R.string.cdc_mp3 + "audio/mp4", + "audio/mp4a-latm", + "audio/mpeg4-generic" -> R.string.cdc_mp4 + "audio/aac", + "audio/aacp", + "audio/3gpp", + "audio/3gpp2" -> R.string.cdc_aac + "audio/ogg", + "application/ogg", + "application/x-ogg" -> R.string.cdc_ogg + "audio/flac" -> R.string.cdc_flac + "audio/wav", + "audio/x-wav", + "audio/wave", + "audio/vnd.wave" -> R.string.cdc_wav + "audio/x-matroska" -> R.string.cdc_mka + else -> -1 + } + + return if (extensionName > -1) { + context.getString(extensionName) } else { // Fall back to the extension if we can't find a special name for this format. MimeTypeMap.getSingleton().getExtensionFromMimeType(fromExtension)?.uppercase() diff --git a/app/src/main/java/org/oxycblt/auxio/music/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/Indexer.kt index 7152c70e6..bcddeeb3a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Indexer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Indexer.kt @@ -179,7 +179,11 @@ class Indexer { private fun indexImpl(context: Context, generation: Long): MusicStore.Library? { emitIndexing(Indexing.Indeterminate, generation) - // Establish the backend to use when initially loading songs. + // Since we have different needs for each version, we determine a "Backend" to use + // when loading music and then leverage that to create the initial song list. + // This is technically dependency injection. Except it doesn't increase your compile + // times by 3x. Isn't that nice. + val mediaStoreBackend = when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> Api30MediaStoreBackend() diff --git a/app/src/main/java/org/oxycblt/auxio/music/IndexerService.kt b/app/src/main/java/org/oxycblt/auxio/music/IndexerService.kt index e5441fa64..8dff997c0 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/IndexerService.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/IndexerService.kt @@ -40,7 +40,10 @@ import org.oxycblt.auxio.util.newMainPendingIntent * A [Service] that handles the music loading process. * * Loading music is actually somewhat time-consuming, to the point where it's likely better suited - * to a service that is less likely to be + * to a service that is less likely to be killed by the OS. + * + * You could probably do the same using WorkManager and the GooberQueue library or whatever, but the + * boilerplate you skip is not worth the insanity of androidx. * * @author OxygenCobalt */ diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt index 5fa05b885..0b3e2950e 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt @@ -37,7 +37,8 @@ class MediaButtonReceiver : BroadcastReceiver() { val playbackManager = PlaybackStateManager.getInstance() if (playbackManager.song != null) { // We have a song, so we can assume that the service will start a foreground state. - // At least, I hope. + // At least, I hope. Again, *this is why we don't do this, I cannot describe how + // stupid this is with the state of foreground services on modern android* intent.component = ComponentName(context, PlaybackService::class.java) ContextCompat.startForegroundService(context, intent) } diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 9f8cb8e66..2832c3934 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -9,8 +9,8 @@ %d - Ogg Vorbis - Ogg Opus + Vorbis + Opus Microsoft WAVE diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd0a23593..b367be498 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -185,6 +185,8 @@ MPEG-4 Audio Ogg Audio Matroska Audio + Advanced Audio Coding (AAC) + Free Lossless Audio Codec (FLAC) Red