all: tweak package structure

Try to tweak the package structure to be more coherent.
This commit is contained in:
Alexander Capehart 2022-09-25 20:23:31 -06:00
parent 3e73cd8080
commit f3c14b81cb
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
42 changed files with 190 additions and 201 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<Song>) : MusicParent(
*/
class Artist
constructor(raw: Raw, songAlbums: List<Music>) : 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

View file

@ -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
/**

View file

@ -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

View file

@ -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

View file

@ -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<String> {
return splitEscaped { separators.contains(it) }
}
/** Parse a multi-value tag into a [ReleaseType], handling separators in the process. */
fun List<String>.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

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.settings
package org.oxycblt.auxio.music.extractor
import android.os.Bundle
import android.view.LayoutInflater

View file

@ -15,13 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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

View file

@ -15,9 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<Directory>, val shouldInclude: Boolean)

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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

View file

@ -15,10 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<out String>,
selector: String? = null,
args: Array<String>? = null
) = query(uri, projection, selector, args, null)
/** Shortcut for making a [ContentResolver] query and using the particular cursor with [use]. */
inline fun <reified R> ContentResolver.useQuery(
uri: Uri,
projection: Array<out String>,
selector: String? = null,
args: Array<String>? = 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)
}
}
}

View file

@ -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<FragmentPlaybackBarBinding>() {
}
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<FragmentPlaybackBarBinding>() {
override fun onDestroyBinding(binding: FragmentPlaybackBarBinding) {
super.onDestroyBinding(binding)
binding.playbackSong.isSelected = false
binding.playbackInfo.isSelected = false
}
private fun updateSong(song: Song?) {

View file

@ -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

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.playback.ui
package org.oxycblt.auxio.playback
import android.content.Context
import android.graphics.drawable.LayerDrawable

View file

@ -15,59 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<out String>,
selector: String? = null,
args: Array<String>? = null
) = query(uri, projection, selector, args, null)
/** Shortcut for making a [ContentResolver] query and using the particular cursor with [use]. */
inline fun <reified R> ContentResolver.useQuery(
uri: Uri,
projection: Array<out String>,
selector: String? = null,
args: Array<String>? = 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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.settings
package org.oxycblt.auxio.settings.prefs
import android.content.Context
import android.content.res.TypedArray

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.settings
package org.oxycblt.auxio.settings.prefs
import android.os.Bundle
import androidx.preference.PreferenceDialogFragmentCompat

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.settings
package org.oxycblt.auxio.settings.prefs
import android.content.Context
import android.util.AttributeSet

View file

@ -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:
*

View file

@ -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">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/playback_bar_fragment"

View file

@ -22,7 +22,7 @@
style="@style/Widget.Auxio.DisableDropShadows"
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">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/playback_bar_fragment"

View file

@ -36,12 +36,13 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_tiny"
android:ellipsize="end"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
app:layout_constraintBottom_toBottomOf="@+id/playback_cover"
app:layout_constraintEnd_toStartOf="@+id/playback_controls_wrapper"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintTop_toBottomOf="@+id/playback_song"
tools:text="Artist Name / Album Name" />
tools:text="Artist Name" />
<org.oxycblt.auxio.playback.ui.ForcedLTRFrameLayout
android:id="@+id/playback_controls_wrapper"

View file

@ -26,7 +26,7 @@
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_list_fragment"
android:name="org.oxycblt.auxio.settings.SettingsListFragment"
android:name="org.oxycblt.auxio.settings.prefs.SettingsListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"

View file

@ -84,12 +84,12 @@
tools:layout="@layout/dialog_pre_amp" />
<dialog
android:id="@+id/music_dirs_dialog"
android:name="org.oxycblt.auxio.music.settings.MusicDirsDialog"
android:name="org.oxycblt.auxio.music.storage.MusicDirsDialog"
android:label="music_dirs_dialog"
tools:layout="@layout/dialog_music_dirs" />
<dialog
android:id="@+id/separators_dialog"
android:name="org.oxycblt.auxio.music.settings.SeparatorsDialog"
android:name="org.oxycblt.auxio.music.extractor.SeparatorsDialog"
android:label="music_dirs_dialog"
tools:layout="@layout/dialog_separators" />

View file

@ -237,7 +237,7 @@
<string name="set_exclude_non_music_desc">Ignore audio files that are not music, such as podcasts</string>
<string name="set_separators">Multi-value separators</string>
<string name="set_separators_desc">Configure characters that denote multiple tag values</string>
<string name="set_separators_warning">Warning: Using this setting may result in some tags being incorrectly interpreted as having multiple values.</string>
<string name="set_separators_warning">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 (\\).</string>
<string name="set_separators_comma">Comma (,)</string>
<string name="set_separators_semicolon">Semicolon (;)</string>
<string name="set_separators_slash">Slash (/)</string>

View file

@ -2,7 +2,7 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/set_ui">
<org.oxycblt.auxio.settings.IntListPreference
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/theme_auto"
app:entries="@array/entries_theme"
app:entryIcons="@array/icons_theme"
@ -11,7 +11,7 @@
app:key="@string/set_key_theme"
app:title="@string/set_theme" />
<org.oxycblt.auxio.settings.WrappedDialogPreference
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
app:icon="@drawable/ic_accent_24"
app:key="@string/set_key_accent"
app:title="@string/set_accent" />
@ -26,7 +26,7 @@
<PreferenceCategory app:title="@string/set_display">
<org.oxycblt.auxio.settings.WrappedDialogPreference
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
app:key="@string/set_key_lib_tabs"
app:summary="@string/set_lib_tabs_desc"
app:title="@string/set_lib_tabs" />
@ -50,7 +50,7 @@
app:summary="@string/set_round_mode_desc"
app:title="@string/set_round_mode" />
<org.oxycblt.auxio.settings.IntListPreference
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/bar_action_next"
app:entries="@array/entries_bar_action"
app:entryValues="@array/values_bar_action"
@ -73,14 +73,14 @@
app:summary="@string/set_headset_autoplay_desc"
app:title="@string/set_headset_autoplay" />
<org.oxycblt.auxio.settings.IntListPreference
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/replay_gain_dynamic"
app:entries="@array/entries_replay_gain"
app:entryValues="@array/values_replay_gain"
app:key="@string/set_key_replay_gain"
app:title="@string/set_replay_gain" />
<org.oxycblt.auxio.settings.WrappedDialogPreference
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
app:key="@string/set_key_pre_amp"
app:summary="@string/set_pre_amp_desc"
app:title="@string/set_pre_amp" />
@ -89,7 +89,7 @@
<PreferenceCategory app:title="@string/set_behavior">
<org.oxycblt.auxio.settings.IntListPreference
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/music_mode_songs"
app:entries="@array/entries_library_song_playback_mode"
app:entryValues="@array/values_library_song_playback_mode"
@ -97,7 +97,7 @@
app:title="@string/set_library_song_playback_mode"
app:useSimpleSummaryProvider="true" />
<org.oxycblt.auxio.settings.IntListPreference
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/music_mode_none"
app:entries="@array/entries_detail_song_playback_mode"
app:entryValues="@array/values_detail_song_playback_mode"
@ -159,12 +159,12 @@
app:summary="@string/set_exclude_non_music_desc"
app:title="@string/set_exclude_non_music" />
<org.oxycblt.auxio.settings.WrappedDialogPreference
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
app:key="@string/set_key_music_dirs"
app:summary="@string/set_dirs_desc"
app:title="@string/set_dirs" />
<org.oxycblt.auxio.settings.WrappedDialogPreference
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
app:key="@string/set_key_separators"
app:summary="@string/set_separators_desc"
app:title="@string/set_separators" />