all: tie up loose ends
Tie up some loose ends before 3.0.0's release.
This commit is contained in:
parent
94e1b71d9b
commit
32db8a591a
8 changed files with 43 additions and 39 deletions
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<DialogSeparatorsBinding>() {
|
||||
// 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<DialogSeparatorsBinding>() {
|
|||
.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<DialogSeparatorsBinding>() {
|
|||
// 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<DialogSeparatorsBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
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 = ';'
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue