diff --git a/app/build.gradle b/app/build.gradle index f5cd92af5..09e3c64dc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -96,12 +96,6 @@ dependencies { // Preferences implementation "androidx.preference:preference-ktx:1.2.0" - // Room - def room_version = "2.4.3" - implementation "androidx.room:room-runtime:$room_version" - kapt "androidx.room:room-compiler:$room_version" - implementation "androidx.room:room-ktx:$room_version" - // --- THIRD PARTY --- // Exoplayer diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 200b25bd5..3d2bf0009 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -21,7 +21,7 @@ #-renamesourcefileattribute SourceFile -keep class org.oxycblt.auxio.AuxioApp --keep class org.oxycblt.auxio.settings.SettingsListFragment +-keep class org.oxycblt.auxio.settings.prefs.SettingsListFragment # Free software does not obsfucate. Also it's easier to debug stack traces. -dontobfuscate \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index 11cbfd59f..6b2dd70d0 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -36,7 +36,7 @@ import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.queue.QueueSheetBehavior -import org.oxycblt.auxio.playback.ui.PlaybackSheetBehavior +import org.oxycblt.auxio.playback.PlaybackSheetBehavior import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.fragment.ViewBindingFragment diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt index aa46b4608..a47778814 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -33,12 +33,12 @@ 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.MimeType import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.ReleaseType import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Sort +import org.oxycblt.auxio.music.storage.MimeType import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.recycler.Header import org.oxycblt.auxio.ui.recycler.Item 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 e79b9fcf6..c1db57ab2 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt @@ -26,7 +26,7 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogSongDetailBinding -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.collectImmediately 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 af2dba420..827560a3d 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 @@ -29,7 +29,7 @@ import org.oxycblt.auxio.databinding.ItemDiscHeaderBinding import org.oxycblt.auxio.detail.DiscHeader import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.ui.recycler.MenuItemListener @@ -120,7 +120,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite binding.detailInfo.apply { val date = - item.date?.let { context.getString(R.string.fmt_number, it.year) } + item.date?.resolveYear(context) ?: context.getString(R.string.def_date) val songCount = context.getPlural(R.plurals.fmt_song_count, item.songs.size) 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 3301028eb..61ffc7bf1 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 @@ -29,7 +29,6 @@ import org.oxycblt.auxio.databinding.ItemSongBinding import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.resolveYear import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.ui.recycler.MenuItemListener @@ -158,7 +157,10 @@ private class ArtistAlbumViewHolder private constructor(private val binding: Ite fun bind(item: Album, listener: MenuItemListener) { binding.parentImage.bind(item) binding.parentName.text = item.resolveName(binding.context) - binding.parentInfo.text = item.date.resolveYear(binding.context) + binding.parentInfo.text = + item.date?.resolveYear(binding.context) + ?: binding.context.getString(R.string.def_date) + // binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.root.setOnLongClickListener { listener.onOpenMenu(item, it) 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 cc9e6354b..72bd46675 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 @@ -26,7 +26,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.ItemDetailBinding import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.ui.recycler.SimpleItemCallback import org.oxycblt.auxio.ui.recycler.SongViewHolder diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt index 2d66e7642..409f96b44 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt @@ -27,8 +27,8 @@ import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.music.formatDurationMs -import org.oxycblt.auxio.music.secsToMs +import org.oxycblt.auxio.playback.formatDurationMs +import org.oxycblt.auxio.playback.secsToMs import org.oxycblt.auxio.ui.recycler.AlbumViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt index 7bd2e948c..819e9028d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt @@ -26,7 +26,7 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.recycler.ArtistViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt index f64b19204..1ef2d0023 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt @@ -26,7 +26,7 @@ import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.recycler.GenreViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt index 8ed2041be..cd761366c 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt @@ -28,9 +28,9 @@ import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.music.formatDurationMs import org.oxycblt.auxio.music.picker.PickerMode -import org.oxycblt.auxio.music.secsToMs +import org.oxycblt.auxio.playback.formatDurationMs +import org.oxycblt.auxio.playback.secsToMs import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.recycler.IndicatorAdapter 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 13e6998ae..2bfea4723 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -26,7 +26,12 @@ import kotlinx.parcelize.Parcelize import org.oxycblt.auxio.R import org.oxycblt.auxio.music.extractor.parseId3GenreNames import org.oxycblt.auxio.music.extractor.parseMultiValue -import org.oxycblt.auxio.music.extractor.parseReleaseType +import org.oxycblt.auxio.music.extractor.toUuidOrNull +import org.oxycblt.auxio.music.storage.Directory +import org.oxycblt.auxio.music.storage.MimeType +import org.oxycblt.auxio.music.storage.Path +import org.oxycblt.auxio.music.storage.albumCoverUri +import org.oxycblt.auxio.music.storage.audioUri import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.nonZeroOrNull @@ -358,7 +363,7 @@ class Song constructor(raw: Raw, settings: Settings) : Music() { musicBrainzId = raw.albumMusicBrainzId?.toUuidOrNull(), name = requireNotNull(raw.albumName) { "Invalid raw: No album name" }, sortName = raw.albumSortName, - releaseType = raw.albumReleaseTypes.parseReleaseType(settings), + releaseType = ReleaseType.parse(raw.albumReleaseTypes.parseMultiValue(settings)), rawArtists = rawAlbumArtists.ifEmpty { rawArtists }.ifEmpty { listOf(Artist.Raw(null, null)) } ) @@ -557,7 +562,9 @@ class Album constructor(raw: Raw, override val songs: List) : MusicParent( */ class Artist constructor(raw: Raw, songAlbums: List) : MusicParent() { - override val uid = raw.musicBrainzId?.let { UID.musicBrainz(MusicMode.ARTISTS, it) } ?: UID.auxio(MusicMode.ARTISTS) { update(raw.name) } + override val uid = raw.musicBrainzId?.let { UID.musicBrainz(MusicMode.ARTISTS, it) } ?: UID.auxio( + MusicMode.ARTISTS + ) { update(raw.name) } override val rawName = raw.name diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt index 02300b9bc..bb4c0aaa4 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicStore.kt @@ -22,6 +22,7 @@ import android.net.Uri import android.provider.OpenableColumns import org.oxycblt.auxio.music.MusicStore.Callback import org.oxycblt.auxio.music.MusicStore.Library +import org.oxycblt.auxio.music.storage.useQuery import org.oxycblt.auxio.util.contentResolverSafe /** diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt index 56b3a0b88..fac336783 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt @@ -26,13 +26,13 @@ import android.provider.MediaStore import androidx.annotation.RequiresApi import androidx.core.database.getIntOrNull import androidx.core.database.getStringOrNull -import org.oxycblt.auxio.music.Directory import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.directoryCompat -import org.oxycblt.auxio.music.mediaStoreVolumeNameCompat -import org.oxycblt.auxio.music.queryCursor -import org.oxycblt.auxio.music.storageVolumesCompat -import org.oxycblt.auxio.music.useQuery +import org.oxycblt.auxio.music.storage.Directory +import org.oxycblt.auxio.music.storage.directoryCompat +import org.oxycblt.auxio.music.storage.mediaStoreVolumeNameCompat +import org.oxycblt.auxio.music.storage.queryCursor +import org.oxycblt.auxio.music.storage.storageVolumesCompat +import org.oxycblt.auxio.music.storage.useQuery import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.util.contentResolverSafe import org.oxycblt.auxio.util.getSystemServiceCompat 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 20bde63e6..0d5e20421 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 @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.metadata.id3.TextInformationFrame import com.google.android.exoplayer2.metadata.vorbis.VorbisComment import org.oxycblt.auxio.music.Date import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.audioUri +import org.oxycblt.auxio.music.storage.audioUri import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logW diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/ParsingUtil.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/ParsingUtil.kt index b0e0e7e74..5db18f3fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/ParsingUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/ParsingUtil.kt @@ -19,9 +19,9 @@ package org.oxycblt.auxio.music.extractor import androidx.core.text.isDigitsOnly import org.oxycblt.auxio.music.Date -import org.oxycblt.auxio.music.ReleaseType import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.util.nonZeroOrNull +import java.util.UUID /** * Parse out the track number field as if the given Int is formatted as DTTT, where D Is the disc @@ -110,8 +110,11 @@ fun String.maybeParseSeparators(settings: Settings): List { return splitEscaped { separators.contains(it) } } -/** Parse a multi-value tag into a [ReleaseType], handling separators in the process. */ -fun List.parseReleaseType(settings: Settings) = ReleaseType.parse(parseMultiValue(settings)) +fun String.toUuidOrNull(): UUID? = try { + UUID.fromString(this) +} catch (e: IllegalArgumentException) { + null +} /** * Parse a multi-value genre name using ID3v2 rules. If there is one value, the ID3v2.3 rules will diff --git a/app/src/main/java/org/oxycblt/auxio/music/settings/SeparatorsDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/music/settings/SeparatorsDialog.kt rename to app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt index 1e0d3ba12..71fd596a8 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/settings/SeparatorsDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/SeparatorsDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.settings +package org.oxycblt.auxio.music.extractor import android.os.Bundle import android.view.LayoutInflater diff --git a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirAdapter.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirAdapter.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirAdapter.kt rename to app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirAdapter.kt index f39b64fad..705659072 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirAdapter.kt @@ -15,13 +15,12 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.settings +package org.oxycblt.auxio.music.storage import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.ItemMusicDirBinding -import org.oxycblt.auxio.music.Directory import org.oxycblt.auxio.ui.recycler.DialogViewHolder import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.inflater diff --git a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirs.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirs.kt similarity index 91% rename from app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirs.kt rename to app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirs.kt index 61db8e10c..7345ea178 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirs.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirs.kt @@ -15,9 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.settings - -import org.oxycblt.auxio.music.Directory +package org.oxycblt.auxio.music.storage /** Represents a the configuration for the "Folder Management" setting */ data class MusicDirs(val dirs: List, val shouldInclude: Boolean) diff --git a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirsDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirsDialog.kt rename to app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt index 74ac2c280..0aa02cb32 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/settings/MusicDirsDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.settings +package org.oxycblt.auxio.music.storage import android.net.Uri import android.os.Bundle @@ -28,7 +28,6 @@ import androidx.core.view.isVisible import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogMusicDirsBinding -import org.oxycblt.auxio.music.Directory import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment import org.oxycblt.auxio.util.context diff --git a/app/src/main/java/org/oxycblt/auxio/music/StorageFramework.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt similarity index 87% rename from app/src/main/java/org/oxycblt/auxio/music/StorageFramework.kt rename to app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt index 02ae96e98..d378e2d64 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/StorageFramework.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt @@ -15,10 +15,14 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music +package org.oxycblt.auxio.music.storage import android.annotation.SuppressLint +import android.content.ContentResolver +import android.content.ContentUris import android.content.Context +import android.database.Cursor +import android.net.Uri import android.os.Build import android.os.Environment import android.os.storage.StorageManager @@ -91,6 +95,107 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: } } +/** + * Represents a mime type as it is loaded by Auxio. [fromExtension] is based on the file extension + * should always exist, while [fromFormat] is based on the file itself and may not be available. + * @author OxygenCobalt + */ +data class MimeType(val fromExtension: String, val fromFormat: String?) { + fun resolveName(context: Context): String { + // 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 + } + + 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() + ?: context.getString(R.string.def_codec) + } + } +} + +/** Shortcut for making a [ContentResolver] query with less superfluous arguments. */ +fun ContentResolver.queryCursor( + uri: Uri, + projection: Array, + selector: String? = null, + args: Array? = null +) = query(uri, projection, selector, args, null) + +/** Shortcut for making a [ContentResolver] query and using the particular cursor with [use]. */ +inline fun ContentResolver.useQuery( + uri: Uri, + projection: Array, + selector: String? = null, + args: Array? = null, + block: (Cursor) -> R +) = queryCursor(uri, projection, selector, args)?.use(block) + +/** + * For some reason the album cover URI namespace does not have a member in [MediaStore], but it + * still works since at least API 21. + */ +private val EXTERNAL_ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart") + +/** Converts a [Long] Audio ID into a URI to that particular audio file. */ +val Long.audioUri: Uri + get() = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, this) + +/** Converts a [Long] Album ID into a URI pointing to MediaStore-cached album art. */ +val Long.albumCoverUri: Uri + get() = ContentUris.withAppendedId(EXTERNAL_ALBUM_ART_URI, this) + @Suppress("NewApi") private val SM_API21_GET_VOLUME_LIST_METHOD: Method by lazyReflectedMethod(StorageManager::class, "getVolumeList") @@ -181,73 +286,3 @@ val StorageVolume.mediaStoreVolumeNameCompat: String? uuidCompat?.lowercase() } } - -/** - * Represents a mime type as it is loaded by Auxio. [fromExtension] is based on the file extension - * should always exist, while [fromFormat] is based on the file itself and may not be available. - * @author OxygenCobalt - */ -data class MimeType(val fromExtension: String, val fromFormat: String?) { - fun resolveName(context: Context): String { - // 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 - } - - 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() - ?: context.getString(R.string.def_codec) - } - } -} 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 3c19f4d85..108fa3ce6 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt @@ -24,7 +24,6 @@ import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.msToDs import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.MainNavigationAction @@ -63,6 +62,7 @@ class PlaybackBarFragment : ViewBindingFragment() { } binding.playbackSong.isSelected = true + binding.playbackInfo.isSelected = true // Load the track color in manually as it's unclear whether the track actually supports // using a ColorStateList in the resources @@ -111,6 +111,7 @@ class PlaybackBarFragment : ViewBindingFragment() { override fun onDestroyBinding(binding: FragmentPlaybackBarBinding) { super.onDestroyBinding(binding) binding.playbackSong.isSelected = false + binding.playbackInfo.isSelected = false } private fun updateSong(song: Song?) { 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 80cf949b2..6cc121b9f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -32,7 +32,6 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.msToDs import org.oxycblt.auxio.music.picker.PickerMode import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.ui.StyledSeekBar diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt rename to app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt index de8dec70b..04547a86b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback.ui +package org.oxycblt.auxio.playback import android.content.Context import android.graphics.drawable.LayerDrawable diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt similarity index 58% rename from app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt rename to app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt index 0ebc533c4..9b6886353 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt @@ -15,59 +15,10 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music +package org.oxycblt.auxio.playback -import android.content.ContentResolver -import android.content.ContentUris -import android.content.Context -import android.database.Cursor -import android.net.Uri -import android.provider.MediaStore import android.text.format.DateUtils -import org.oxycblt.auxio.R import org.oxycblt.auxio.util.logD -import java.util.UUID - -/** Shortcut for making a [ContentResolver] query with less superfluous arguments. */ -fun ContentResolver.queryCursor( - uri: Uri, - projection: Array, - selector: String? = null, - args: Array? = null -) = query(uri, projection, selector, args, null) - -/** Shortcut for making a [ContentResolver] query and using the particular cursor with [use]. */ -inline fun ContentResolver.useQuery( - uri: Uri, - projection: Array, - selector: String? = null, - args: Array? = null, - block: (Cursor) -> R -) = queryCursor(uri, projection, selector, args)?.use(block) - -/** - * For some reason the album cover URI namespace does not have a member in [MediaStore], but it - * still works since at least API 21. - */ -private val EXTERNAL_ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart") - -/** Converts a [Long] Audio ID into a URI to that particular audio file. */ -val Long.audioUri: Uri - get() = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, this) - -/** Converts a [Long] Album ID into a URI pointing to MediaStore-cached album art. */ -val Long.albumCoverUri: Uri - get() = ContentUris.withAppendedId(EXTERNAL_ALBUM_ART_URI, this) - -fun String.toUuidOrNull(): UUID? = try { - UUID.fromString(this) -} catch (e: IllegalArgumentException) { - null -} - -/** Shortcut to resolve a year from a nullable date. Will return "No Date" if it is null. */ -fun Date?.resolveYear(context: Context) = - this?.resolveYear(context) ?: context.getString(R.string.def_date) /** Converts a long in milliseconds to a long in deci-seconds */ fun Long.msToDs() = floorDiv(100) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index 7d1053fe6..c86ad8753 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -30,8 +30,6 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.dsToMs -import org.oxycblt.auxio.music.msToDs import org.oxycblt.auxio.playback.state.InternalPlayer import org.oxycblt.auxio.playback.state.PlaybackStateDatabase import org.oxycblt.auxio.playback.state.PlaybackStateManager diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt index 106c870f7..f8cc0db9f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt @@ -21,7 +21,7 @@ import android.content.Context import android.util.AttributeSet import com.google.android.material.slider.Slider import org.oxycblt.auxio.databinding.ViewSeekBarBinding -import org.oxycblt.auxio.music.formatDurationDs +import org.oxycblt.auxio.playback.formatDurationDs import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.logD import kotlin.math.max diff --git a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt index dfc14b49a..e9a4a6662 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt @@ -36,7 +36,7 @@ import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.formatDurationMs +import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.fragment.ViewBindingFragment import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.collectImmediately 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 e449d2f95..3c2b760cb 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -27,10 +27,10 @@ import androidx.preference.PreferenceManager import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R import org.oxycblt.auxio.home.tabs.Tab -import org.oxycblt.auxio.music.Directory import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.music.settings.MusicDirs +import org.oxycblt.auxio.music.storage.Directory +import org.oxycblt.auxio.music.storage.MusicDirs import org.oxycblt.auxio.playback.BarAction import org.oxycblt.auxio.playback.replaygain.ReplayGainMode import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp diff --git a/app/src/main/java/org/oxycblt/auxio/settings/IntListPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreference.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/settings/IntListPreference.kt rename to app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreference.kt index 95c5bcb37..c18fed2c8 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/IntListPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreference.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.settings +package org.oxycblt.auxio.settings.prefs import android.content.Context import android.content.res.TypedArray diff --git a/app/src/main/java/org/oxycblt/auxio/settings/IntListPreferenceDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreferenceDialog.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/settings/IntListPreferenceDialog.kt rename to app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreferenceDialog.kt index 51a6c261c..02baa6868 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/IntListPreferenceDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/IntListPreferenceDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.settings +package org.oxycblt.auxio.settings.prefs import android.os.Bundle import androidx.preference.PreferenceDialogFragmentCompat diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt rename to app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt index 7f2600a88..54a2c60de 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.settings +package org.oxycblt.auxio.settings.prefs import android.os.Bundle import android.view.View @@ -33,6 +33,7 @@ import coil.Coil import org.oxycblt.auxio.R import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.playback.PlaybackViewModel +import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.isNight diff --git a/app/src/main/java/org/oxycblt/auxio/settings/WrappedDialogPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/WrappedDialogPreference.kt similarity index 96% rename from app/src/main/java/org/oxycblt/auxio/settings/WrappedDialogPreference.kt rename to app/src/main/java/org/oxycblt/auxio/settings/prefs/WrappedDialogPreference.kt index f3e0436f4..77ccd7607 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/WrappedDialogPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/WrappedDialogPreference.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.settings +package org.oxycblt.auxio.settings.prefs import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt index f60b054e1..427dfc3d9 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt @@ -50,14 +50,14 @@ private val Any.autoTag: String get() = "Auxio.${this::class.simpleName ?: "Anonymous Object"}" /** - * I know that this will not stop you, but consider what you are doing with your life, plagiarizers. + * Note: If you are politely forking this project while keeping the source open, you can ignore + * the following passage. If not, give me a moment of your time. * - * Do you want to live a fulfilling existence on this planet? Or do you want to spend your life - * taking work others did and making it objectively worse so you could arbitrage a fraction of a - * penny on every AdMob impression you get? - * - * You could do so many great things if you simply had the courage to come up with an idea of your - * own. + * Consider what you are doing with your life, plagiarizers. Do you want to live a fulfilling + * existence on this planet? Or do you want to spend your life taking work others did and making + * it objectively worse so you could arbitrage a fraction of a penny on every AdMob impression you + * get? You could do so many great things if you simply had the courage to come up with an idea of + * your own. * * If you still want to go on, I guess the only thing I can say is this: * diff --git a/app/src/main/res/layout-w600dp-land/fragment_main.xml b/app/src/main/res/layout-w600dp-land/fragment_main.xml index c757e7f93..a4a0fd849 100644 --- a/app/src/main/res/layout-w600dp-land/fragment_main.xml +++ b/app/src/main/res/layout-w600dp-land/fragment_main.xml @@ -20,7 +20,7 @@ android:id="@+id/playback_sheet" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_behavior="org.oxycblt.auxio.playback.ui.PlaybackSheetBehavior"> + app:layout_behavior="org.oxycblt.auxio.playback.PlaybackSheetBehavior"> + app:layout_behavior="org.oxycblt.auxio.playback.PlaybackSheetBehavior"> + tools:text="Artist Name" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5f13eb4fa..2c93da56f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -237,7 +237,7 @@ Ignore audio files that are not music, such as podcasts Multi-value separators Configure characters that denote multiple tag values - Warning: Using this setting may result in some tags being incorrectly interpreted as having multiple values. + Warning: Using this setting may result in some tags being incorrectly interpreted as having multiple values. You can resolve this by escaping unwanted separator characters with a backslash (\\). Comma (,) Semicolon (;) Slash (/) diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index a28872f65..f53463333 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -2,7 +2,7 @@ - - @@ -26,7 +26,7 @@ - @@ -50,7 +50,7 @@ app:summary="@string/set_round_mode_desc" app:title="@string/set_round_mode" /> - - - @@ -89,7 +89,7 @@ - - - -