diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a991d7c4..a92b01e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ audio focus was lost - "Show covers" and "Ignore MediaStore covers" have been unified into "Album covers" #### Dev/Meta +- Created new wiki with more information about app functionality - Completed migration to reactive playback system - Refactor music backends into a unified chain of extractors - Add bluetooth connection reciever (No functionality in app yet) diff --git a/app/src/main/java/org/oxycblt/auxio/music/Music.kt b/app/src/main/java/org/oxycblt/auxio/music/Music.kt index af1ef16fb..aa424003c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -345,7 +345,7 @@ class Song constructor(raw: Raw, settings: Settings) : Music() { val mimeType = MimeType( fromExtension = requireNotNull(raw.extensionMimeType) { "Invalid raw: No mime type" }, - fromFormat = raw.formatMimeType) + fromFormat = null) /** The size of the audio file, in bytes. */ val size = requireNotNull(raw.size) { "Invalid raw: No size" } @@ -547,8 +547,6 @@ class Song constructor(raw: Raw, settings: Settings) : Music() { var durationMs: Long? = null, /** @see Song.mimeType */ var extensionMimeType: String? = null, - /** @see Song.mimeType */ - var formatMimeType: String? = null, /** @see Music.UID */ var musicBrainzId: String? = null, /** @see Music.rawName */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt index a5189c242..ca371c0fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt @@ -132,7 +132,6 @@ class ReadWriteCacheExtractor(private val context: Context) : WriteOnlyCacheExtr rawSong.size = cachedRawSong.size rawSong.durationMs = cachedRawSong.durationMs - rawSong.formatMimeType = cachedRawSong.formatMimeType rawSong.track = cachedRawSong.track rawSong.disc = cachedRawSong.disc @@ -180,7 +179,6 @@ private class CacheDatabase(context: Context) : append("${Columns.DATE_MODIFIED} LONG NOT NULL,") append("${Columns.SIZE} LONG NOT NULL,") append("${Columns.DURATION} LONG NOT NULL,") - append("${Columns.FORMAT_MIME_TYPE} STRING,") append("${Columns.MUSIC_BRAINZ_ID} STRING,") append("${Columns.NAME} STRING NOT NULL,") append("${Columns.SORT_NAME} STRING,") @@ -236,7 +234,6 @@ private class CacheDatabase(context: Context) : val sizeIndex = cursor.getColumnIndexOrThrow(Columns.SIZE) val durationIndex = cursor.getColumnIndexOrThrow(Columns.DURATION) - val formatMimeTypeIndex = cursor.getColumnIndexOrThrow(Columns.FORMAT_MIME_TYPE) val musicBrainzIdIndex = cursor.getColumnIndexOrThrow(Columns.MUSIC_BRAINZ_ID) val nameIndex = cursor.getColumnIndexOrThrow(Columns.NAME) @@ -275,7 +272,6 @@ private class CacheDatabase(context: Context) : raw.size = cursor.getLong(sizeIndex) raw.durationMs = cursor.getLong(durationIndex) - raw.formatMimeType = cursor.getStringOrNull(formatMimeTypeIndex) raw.musicBrainzId = cursor.getStringOrNull(musicBrainzIdIndex) raw.name = cursor.getString(nameIndex) @@ -341,7 +337,6 @@ private class CacheDatabase(context: Context) : put(Columns.SIZE, rawSong.size) put(Columns.DURATION, rawSong.durationMs) - put(Columns.FORMAT_MIME_TYPE, rawSong.formatMimeType) put(Columns.MUSIC_BRAINZ_ID, rawSong.name) put(Columns.NAME, rawSong.name) @@ -407,8 +402,6 @@ private class CacheDatabase(context: Context) : const val SIZE = "size" /** @see Song.Raw.durationMs */ const val DURATION = "duration" - /** @see Song.Raw.formatMimeType */ - const val FORMAT_MIME_TYPE = "fmt_mime" /** @see Song.Raw.musicBrainzId */ const val MUSIC_BRAINZ_ID = "mbid" /** @see Song.Raw.name */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt index 98f58c530..a0f6b1168 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt @@ -160,10 +160,6 @@ class Task(context: Context, private val raw: Song.Raw) { return raw } - // Populate the format mime type if we have one. - // TODO: Check if this is even useful or not. - format.sampleMimeType?.let { raw.formatMimeType = it } - val metadata = format.metadata if (metadata != null) { populateWithMetadata(metadata) diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt index fde4b7933..c7e2ed55f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt @@ -22,6 +22,7 @@ import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog import androidx.core.view.children import com.google.android.material.checkbox.MaterialCheckBox +import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogSeparatorsBinding import org.oxycblt.auxio.settings.Settings @@ -34,7 +35,6 @@ import org.oxycblt.auxio.util.context * @author Alexander Capehart (OxygenCobalt) */ class SeparatorsDialog : ViewBindingDialogFragment() { - // TODO: Add saved state for pending configurations. private val settings: Settings by lifecycleObject { binding -> Settings(binding.context) } override fun onCreateBinding(inflater: LayoutInflater) = @@ -45,17 +45,7 @@ class SeparatorsDialog : ViewBindingDialogFragment() { .setTitle(R.string.set_separators) .setNegativeButton(R.string.lbl_cancel, null) .setPositiveButton(R.string.lbl_save) { _, _ -> - // Create the separator list based on the checked configuration of each - // view element. It's generally more stable to duplicate this code instead - // of use a mapping that could feasibly drift from the actual layout. - var separators = "" - val binding = requireBinding() - if (binding.separatorComma.isChecked) separators += SEPARATOR_COMMA - if (binding.separatorSemicolon.isChecked) separators += SEPARATOR_SEMICOLON - if (binding.separatorSlash.isChecked) separators += SEPARATOR_SLASH - if (binding.separatorPlus.isChecked) separators += SEPARATOR_PLUS - if (binding.separatorAnd.isChecked) separators += SEPARATOR_AND - settings.musicSeparators = separators + settings.musicSeparators = getCurrentSeparators() } } @@ -71,7 +61,7 @@ class SeparatorsDialog : ViewBindingDialogFragment() { // More efficient to do one iteration through the separator list and initialize // the corresponding CheckBox for each character instead of doing an iteration // through the separator list for each CheckBox. - settings.musicSeparators?.forEach { + (savedInstanceState?.getString(KEY_PENDING_SEPARATORS) ?: settings.musicSeparators)?.forEach { when (it) { SEPARATOR_COMMA -> binding.separatorComma.isChecked = true SEPARATOR_SEMICOLON -> binding.separatorSemicolon.isChecked = true @@ -83,7 +73,28 @@ class SeparatorsDialog : ViewBindingDialogFragment() { } } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(KEY_PENDING_SEPARATORS, getCurrentSeparators()) + } + + /** Get the current separator string configuration from the UI. */ + private fun getCurrentSeparators(): String { + // Create the separator list based on the checked configuration of each + // view element. It's generally more stable to duplicate this code instead + // of use a mapping that could feasibly drift from the actual layout. + var separators = "" + val binding = requireBinding() + if (binding.separatorComma.isChecked) separators += SEPARATOR_COMMA + if (binding.separatorSemicolon.isChecked) separators += SEPARATOR_SEMICOLON + if (binding.separatorSlash.isChecked) separators += SEPARATOR_SLASH + if (binding.separatorPlus.isChecked) separators += SEPARATOR_PLUS + if (binding.separatorAnd.isChecked) separators += SEPARATOR_AND + return separators + } + companion object { + private val KEY_PENDING_SEPARATORS = BuildConfig.APPLICATION_ID + ".key.PENDING_SEPARATORS" // TODO: Move these to a more "Correct" location? private const val SEPARATOR_COMMA = ',' private const val SEPARATOR_SEMICOLON = ';' diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/Storage.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/Storage.kt index 16424a06d..ebe8a0ae2 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/Storage.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/Storage.kt @@ -18,6 +18,8 @@ package org.oxycblt.auxio.music.storage import android.content.Context +import android.media.MediaExtractor +import android.media.MediaFormat import android.os.storage.StorageManager import android.os.storage.StorageVolume import android.webkit.MimeTypeMap @@ -153,17 +155,12 @@ data class MimeType(val fromExtension: String, val fromFormat: String?) { // 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 bother with. - 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 - + MediaFormat.MIMETYPE_AUDIO_MPEG -> R.string.cdc_mp3 + MediaFormat.MIMETYPE_AUDIO_AAC -> R.string.cdc_aac + MediaFormat.MIMETYPE_AUDIO_VORBIS -> R.string.cdc_vorbis + MediaFormat.MIMETYPE_AUDIO_OPUS -> R.string.cdc_opus + MediaFormat.MIMETYPE_AUDIO_FLAC -> R.string.cdc_flac // We don't give a name to more unpopular formats. - else -> -1 } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt index 1899bda53..f0ee563f9 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt @@ -276,9 +276,10 @@ class ReplayGainAudioProcessor(context: Context) : BaseAudioProcessor() { /** * A raw ReplayGain adjustment. * @param key The tag's key. - * @param value The tag's adjustment, in dB. TODO: Try to phasse this out. + * @param value The tag's adjustment, in dB. */ private data class GainTag(val key: String, val value: Float) + // TODO: Try to phase this out companion object { private const val TAG_RG_TRACK = "replaygain_track_gain" diff --git a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt index 18beeddc8..f5711e221 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -165,8 +165,15 @@ class Settings(private val context: Context, private val callback: Callback? = n unlikelyToBeNull(callback).onSettingChanged(key) } - /** TODO: Rework this */ + /** + * Simplified callback for settings changes. + */ interface Callback { + // TODO: Refactor this lifecycle + /** + * Called when a setting has changed. + * @param key The key of the setting that changed. + */ fun onSettingChanged(key: String) }