diff --git a/app/build.gradle b/app/build.gradle index 15c5a46d7..08ec952ac 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,7 +82,7 @@ dependencies { implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.viewpager2:viewpager2:1.1.0-beta01" - implementation 'androidx.core:core-ktx:+' + implementation 'androidx.core:core-ktx:1.9.0' // Lifecycle def lifecycle_version = "2.5.1" diff --git a/app/src/main/java/org/oxycblt/auxio/Auxio.kt b/app/src/main/java/org/oxycblt/auxio/Auxio.kt index 01f4eecab..a4de76821 100644 --- a/app/src/main/java/org/oxycblt/auxio/Auxio.kt +++ b/app/src/main/java/org/oxycblt/auxio/Auxio.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.ui.UISettings /** * A simple, rational music player for android. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltAndroidApp diff --git a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt index 3c724786a..1972449e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt +++ b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt @@ -20,6 +20,7 @@ package org.oxycblt.auxio /** * A table containing all of the magic integer codes that the codebase has currently reserved. May * be non-contiguous. + * * @author Alexander Capehart (OxygenCobalt) */ object IntegerTable { diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index d956bb4ce..5b1fc45c7 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -40,17 +40,13 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * Auxio's single [AppCompatActivity]. * - * TODO: Add error screens - * - * TODO: Custom language support - * - * TODO: Use proper material attributes (Not the weird dimen attributes I currently have) - * - * TODO: Migrate to material animation system - * - * TODO: Unit testing - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Add error screens + * TODO: Custom language support + * TODO: Use proper material attributes (Not the weird dimen attributes I currently have) + * TODO: Migrate to material animation system + * TODO: Unit testing */ @AndroidEntryPoint class MainActivity : AppCompatActivity() { @@ -112,9 +108,10 @@ class MainActivity : AppCompatActivity() { /** * Transform an [Intent] given to [MainActivity] into a [InternalPlayer.Action] that can be used * in the playback system. + * * @param intent The (new) [Intent] given to this [MainActivity], or null if there is no intent. * @return true If the analogous [InternalPlayer.Action] to the given [Intent] was started, - * false otherwise. + * false otherwise. */ private fun startIntentAction(intent: Intent?): Boolean { if (intent == null) { diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index b036dd393..9fc35a74c 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -51,6 +51,7 @@ import org.oxycblt.auxio.util.* /** * A wrapper around the home fragment that shows the playback fragment and controls the more * high-level navigation features. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 74a7eb6bd..fd9bfe960 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -47,6 +47,7 @@ import org.oxycblt.auxio.util.* /** * A [ListFragment] that shows information about an [Album]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index 8bdca12ab..c1a8ab29f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -50,6 +50,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A [ListFragment] that shows information about an [Artist]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint 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 7c738a768..d53a29b6a 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -44,6 +44,7 @@ import org.oxycblt.auxio.util.* /** * [ViewModel] that manages the Song, Album, Artist, and Genre detail views. Keeps track of the * current item they are showing, sub-data to display, and configuration. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -182,6 +183,7 @@ constructor( /** * Set a new [currentSong] from it's [Music.UID]. If the [Music.UID] differs, [currentSong] and * [songAudioInfo] will be updated to align with the new [Song]. + * * @param uid The UID of the [Song] to load. Must be valid. */ fun setSongUid(uid: Music.UID) { @@ -196,6 +198,7 @@ constructor( /** * Set a new [currentAlbum] from it's [Music.UID]. If the [Music.UID] differs, [currentAlbum] * and [albumList] will be updated to align with the new [Album]. + * * @param uid The [Music.UID] of the [Album] to update [currentAlbum] to. Must be valid. */ fun setAlbumUid(uid: Music.UID) { @@ -210,6 +213,7 @@ constructor( /** * Set a new [currentArtist] from it's [Music.UID]. If the [Music.UID] differs, [currentArtist] * and [artistList] will be updated to align with the new [Artist]. + * * @param uid The [Music.UID] of the [Artist] to update [currentArtist] to. Must be valid. */ fun setArtistUid(uid: Music.UID) { @@ -224,6 +228,7 @@ constructor( /** * Set a new [currentGenre] from it's [Music.UID]. If the [Music.UID] differs, [currentGenre] * and [genreList] will be updated to align with the new album. + * * @param uid The [Music.UID] of the [Genre] to update [currentGenre] to. Must be valid. */ fun setGenreUid(uid: Music.UID) { @@ -239,6 +244,7 @@ constructor( /** * Start a new job to load a given [Song]'s [AudioInfo]. Result is pushed to [songAudioInfo]. + * * @param song The song to load. */ private fun refreshAudioInfo(song: Song) { @@ -333,8 +339,9 @@ constructor( /** * A simpler mapping of [ReleaseType] used for grouping and sorting songs. + * * @param headerTitleRes The title string resource to use for a header created out of an - * instance of this enum. + * instance of this enum. */ private enum class AlbumGrouping(@StringRes val headerTitleRes: Int) { ALBUMS(R.string.lbl_albums), diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index ce9fa505c..a032e9717 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -51,6 +51,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A [ListFragment] that shows information for a particular [Genre]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint 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 1ebf9ff46..eac8d0d3d 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt @@ -42,6 +42,7 @@ import org.oxycblt.auxio.util.concatLocalized /** * A [ViewBindingDialogFragment] that shows information about a Song. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint 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 aa573a4e0..32c028d38 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 @@ -43,6 +43,7 @@ import org.oxycblt.auxio.util.inflater /** * An [DetailAdapter] implementing the header and sub-items for the [Album] detail view. + * * @param listener A [Listener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -118,6 +119,7 @@ class AlbumDetailAdapter(private val listener: Listener) : DetailAdapter(listene /** * A [RecyclerView.ViewHolder] that displays the [Album] header in the detail view. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class AlbumDetailViewHolder private constructor(private val binding: ItemDetailBinding) : @@ -125,6 +127,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite /** * Bind new data to this instance. + * * @param album The new [Album] to bind. * @param listener A [AlbumDetailAdapter.Listener] to bind interactions to. */ @@ -164,6 +167,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -187,12 +191,14 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite /** * A [RecyclerView.ViewHolder] that displays a [Disc] to delimit different disc groups. Use [from] * to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class DiscViewHolder(private val binding: ItemDiscHeaderBinding) : RecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param disc The new [disc] to bind. */ fun bind(disc: Disc) { @@ -209,6 +215,7 @@ private class DiscViewHolder(private val binding: ItemDiscHeaderBinding) : /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -227,12 +234,14 @@ private class DiscViewHolder(private val binding: ItemDiscHeaderBinding) : /** * A [RecyclerView.ViewHolder] that displays a [Song] in the context of an [Album]. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class AlbumSongViewHolder private constructor(private val binding: ItemAlbumSongBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param song The new [Song] to bind. * @param listener A [SelectableListListener] to bind interactions to. */ @@ -276,6 +285,7 @@ private class AlbumSongViewHolder private constructor(private val binding: ItemA /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ 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 655577638..5cd7ddda7 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 @@ -37,6 +37,7 @@ import org.oxycblt.auxio.util.inflater /** * A [DetailAdapter] implementing the header and sub-items for the [Artist] detail view. + * * @param listener A [DetailAdapter.Listener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -100,6 +101,7 @@ class ArtistDetailAdapter(private val listener: Listener) : /** * A [RecyclerView.ViewHolder] that displays the [Artist] header in the detail view. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class ArtistDetailViewHolder private constructor(private val binding: ItemDetailBinding) : @@ -107,6 +109,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It /** * Bind new data to this instance. + * * @param artist The new [Artist] to bind. * @param listener A [DetailAdapter.Listener] to bind interactions to. */ @@ -154,6 +157,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -175,12 +179,14 @@ private class ArtistDetailViewHolder private constructor(private val binding: It /** * A [RecyclerView.ViewHolder] that displays an [Album] in the context of an [Artist]. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class ArtistAlbumViewHolder private constructor(private val binding: ItemParentBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param album The new [Album] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -209,6 +215,7 @@ private class ArtistAlbumViewHolder private constructor(private val binding: Ite /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -227,12 +234,14 @@ private class ArtistAlbumViewHolder private constructor(private val binding: Ite /** * A [RecyclerView.ViewHolder] that displays a [Song] in the context of an [Artist]. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class ArtistSongViewHolder private constructor(private val binding: ItemSongBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param song The new [Song] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -258,6 +267,7 @@ private class ArtistSongViewHolder private constructor(private val binding: Item /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt index a529aa5ac..3adaaefa7 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt @@ -37,9 +37,10 @@ import org.oxycblt.auxio.util.inflater /** * A [RecyclerView.Adapter] that implements behavior shared across each detail view's adapters. + * * @param listener A [Listener] to bind interactions to. * @param diffCallback A [DiffUtil.ItemCallback] to use for item comparison when diffing the - * internal list. + * internal list. * @author Alexander Capehart (OxygenCobalt) */ abstract class DetailAdapter( @@ -119,6 +120,7 @@ abstract class DetailAdapter( /** * A header variation that displays a button to open a sort menu. + * * @param titleRes The string resource to use as the header title * @author Alexander Capehart (OxygenCobalt) */ @@ -127,12 +129,14 @@ data class SortHeader(@StringRes override val titleRes: Int) : Header /** * A [RecyclerView.ViewHolder] that displays a [SortHeader], a variation on [BasicHeader] that adds * a button opening a menu for sorting. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class SortHeaderViewHolder(private val binding: ItemSortHeaderBinding) : RecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param sortHeader The new [SortHeader] to bind. * @param listener An [DetailAdapter.Listener] to bind interactions to. */ @@ -152,6 +156,7 @@ private class SortHeaderViewHolder(private val binding: ItemSortHeaderBinding) : /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ 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 51a86f335..927706be1 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 @@ -38,6 +38,7 @@ import org.oxycblt.auxio.util.inflater /** * An [DetailAdapter] implementing the header and sub-items for the [Genre] detail view. + * * @param listener A [DetailAdapter.Listener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -100,12 +101,14 @@ class GenreDetailAdapter(private val listener: Listener) : /** * A [RecyclerView.ViewHolder] that displays the [Genre] header in the detail view. Use [from] to * create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ private class GenreDetailViewHolder private constructor(private val binding: ItemDetailBinding) : RecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param genre The new [Song] to bind. * @param listener A [DetailAdapter.Listener] to bind interactions to. */ @@ -131,6 +134,7 @@ private class GenreDetailViewHolder private constructor(private val binding: Ite /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt index 863a921e5..104d05914 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.util.inflater /** * An adapter for [SongProperty] instances. + * * @author Alexander Capehart (OxygenCobalt) */ class SongPropertyAdapter : @@ -48,6 +49,7 @@ class SongPropertyAdapter : /** * A property entry for use in [SongPropertyAdapter]. + * * @param name The contextual title to use for the property. * @param value The value of the property. * @author Alexander Capehart (OxygenCobalt) @@ -56,6 +58,7 @@ data class SongProperty(@StringRes val name: Int, val value: String) : Item /** * A [RecyclerView.ViewHolder] that displays a [SongProperty]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class SongPropertyViewHolder private constructor(private val binding: ItemSongPropertyBinding) : @@ -69,6 +72,7 @@ class SongPropertyViewHolder private constructor(private val binding: ItemSongPr companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/home/EdgeFrameLayout.kt b/app/src/main/java/org/oxycblt/auxio/home/EdgeFrameLayout.kt index 81fe40edd..b29f45206 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/EdgeFrameLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/EdgeFrameLayout.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [FrameLayout] that automatically applies bottom insets. + * * @author Alexander Capehart (OxygenCobalt) */ class EdgeFrameLayout diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 41a7f2240..c6cc88e07 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -64,6 +64,7 @@ import org.oxycblt.auxio.util.* /** * The starting [SelectionFragment] of Auxio. Shows the user's music library and enables navigation * to other views. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -483,10 +484,11 @@ class HomeFragment : /** * [FragmentStateAdapter] implementation for the [HomeFragment]'s [ViewPager2] instance. + * * @param tabs The current tab configuration. This will define the [Fragment]s created. * @param fragmentManager The [FragmentManager] required by [FragmentStateAdapter]. * @param lifecycleOwner The [LifecycleOwner], whose Lifecycle is required by - * [FragmentStateAdapter]. + * [FragmentStateAdapter]. */ private class HomePagerAdapter( private val tabs: List, diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt index 2499b5918..e677fbbff 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * User configuration specific to the home UI. + * * @author Alexander Capehart (OxygenCobalt) */ interface HomeSettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index 7fe81ed7f..c4afbc64a 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.logD /** * The ViewModel for managing the tab data and lists of the home view. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -138,6 +139,7 @@ constructor( /** * Get the preferred [Sort] for a given [Tab]. + * * @param tabMode The [MusicMode] of the [Tab] desired. * @return The [Sort] preferred for that [Tab] */ @@ -151,6 +153,7 @@ constructor( /** * Update the preferred [Sort] for the current [Tab]. Will update corresponding list. + * * @param sort The new [Sort] to apply. Assumed to be an allowed sort for the current [Tab]. */ fun setSortForCurrentTab(sort: Sort) { @@ -178,6 +181,7 @@ constructor( /** * Update [currentTabMode] to reflect a new ViewPager2 position + * * @param pagerPos The new position of the ViewPager2 instance. */ fun synchronizeTabPosition(pagerPos: Int) { @@ -187,6 +191,7 @@ constructor( /** * Mark the recreation process as complete. + * * @see shouldRecreate */ fun finishRecreate() { @@ -195,6 +200,7 @@ constructor( /** * Update whether the user is fast scrolling or not in the home view. + * * @param isFastScrolling true if the user is currently fast scrolling, false otherwise. */ fun setFastScrolling(isFastScrolling: Boolean) { @@ -204,8 +210,9 @@ constructor( /** * Create a list of [MusicMode]s representing a simpler version of the [Tab] configuration. + * * @return A list of the [MusicMode]s for each visible [Tab] in the configuration, ordered in - * the same way as the configuration. + * the same way as the configuration. */ private fun makeTabModes() = homeSettings.homeTabs.filterIsInstance().map { it.mode } diff --git a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollPopupView.kt b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollPopupView.kt index da7cd4554..6b58ab788 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollPopupView.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollPopupView.kt @@ -40,6 +40,7 @@ import org.oxycblt.auxio.util.isRtl /** * A [MaterialTextView] that displays the popup indicator used in FastScrollRecyclerView + * * @author Alexander Capehart (OxygenCobalt), Hai Zhang */ class FastScrollPopupView diff --git a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt index 863d5b32a..1eddec492 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt @@ -49,7 +49,7 @@ import org.oxycblt.auxio.util.* * * !!! MODIFICATIONS !!!: * - Scroller will no longer show itself on startup or relayouts, which looked unpleasant with - * multiple views + * multiple views * - DefaultAnimationHelper and RecyclerViewHelper were merged into the class * - FastScroller overlay was merged into RecyclerView instance * - Removed FastScrollerBuilder @@ -61,11 +61,10 @@ import org.oxycblt.auxio.util.* * - Added drag listener * - Added documentation * - * TODO: Add vibration when popup changes - * - * TODO: Improve support for variably sized items (Re-back with library fast scroller?) - * * @author Hai Zhang, Alexander Capehart (OxygenCobalt) + * + * TODO: Add vibration when popup changes + * TODO: Improve support for variably sized items (Re-back with library fast scroller?) */ class FastScrollRecyclerView @JvmOverloads @@ -508,9 +507,10 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr interface PopupProvider { /** * Get text to use in the popup at the specified position. + * * @param pos The position in the list. * @return A [String] to use in the popup. Null if there is no applicable text for the popup - * at [pos]. + * at [pos]. */ fun getPopup(pos: Int): String? } @@ -519,6 +519,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr interface Listener { /** * Called when the fast scrolling state changes. + * * @param isFastScrolling true if the user is currently fast scrolling, false otherwise. */ fun onFastScrollingChanged(isFastScrolling: Boolean) 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 8820db820..b937cc0b6 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 @@ -46,6 +46,7 @@ import org.oxycblt.auxio.util.collectImmediately /** * A [ListFragment] that shows a list of [Album]s. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -154,6 +155,7 @@ class AlbumListFragment : /** * A [SelectionIndicatorAdapter] that shows a list of [Album]s using [AlbumViewHolder]. + * * @param listener An [SelectableListListener] to bind interactions to. */ private class AlbumAdapter(private val listener: SelectableListListener) : 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 5d9ec7357..a355c2389 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 @@ -47,6 +47,7 @@ import org.oxycblt.auxio.util.nonZeroOrNull /** * A [ListFragment] that shows a list of [Artist]s. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -132,6 +133,7 @@ class ArtistListFragment : /** * A [SelectionIndicatorAdapter] that shows a list of [Artist]s using [ArtistViewHolder]. + * * @param listener An [SelectableListListener] to bind interactions to. */ private class ArtistAdapter(private val listener: SelectableListListener) : 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 863eb22cb..a70f41e53 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 @@ -46,6 +46,7 @@ import org.oxycblt.auxio.util.collectImmediately /** * A [ListFragment] that shows a list of [Genre]s. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -131,6 +132,7 @@ class GenreListFragment : /** * A [SelectionIndicatorAdapter] that shows a list of [Genre]s using [GenreViewHolder]. + * * @param listener An [SelectableListListener] to bind interactions to. */ private class GenreAdapter(private val listener: SelectableListListener) : 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 1990737df..164d036c7 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 @@ -49,6 +49,7 @@ import org.oxycblt.auxio.util.collectImmediately /** * A [ListFragment] that shows a list of [Song]s. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -165,6 +166,7 @@ class SongListFragment : /** * A [SelectionIndicatorAdapter] that shows a list of [Song]s using [SongViewHolder]. + * * @param listener An [SelectableListListener] to bind interactions to. */ private class SongAdapter(private val listener: SelectableListListener) : diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt index d1a97ba58..fed406024 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.util.logD /** * A [TabLayoutMediator.TabConfigurationStrategy] that uses larger/smaller tab configurations * depending on the screen configuration. + * * @param context [Context] required to obtain window information * @param tabs Current tab configuration from settings * @author Alexander Capehart (OxygenCobalt) diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt index 76f7cf95d..2984ef779 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt @@ -22,18 +22,21 @@ import org.oxycblt.auxio.util.logE /** * A representation of a library tab suitable for configuration. + * * @param mode The type of list in the home view this instance corresponds to. * @author Alexander Capehart (OxygenCobalt) */ sealed class Tab(open val mode: MusicMode) { /** * A visible tab. This will be visible in the home and tab configuration views. + * * @param mode The type of list in the home view this instance corresponds to. */ data class Visible(override val mode: MusicMode) : Tab(mode) /** * A visible tab. This will be visible in the tab configuration view, but not in the home view. + * * @param mode The type of list in the home view this instance corresponds to. */ data class Invisible(override val mode: MusicMode) : Tab(mode) @@ -68,6 +71,7 @@ sealed class Tab(open val mode: MusicMode) { /** * Convert an array of [Tab]s into it's integer representation. + * * @param tabs The array of [Tab]s to convert * @return An integer representation of the [Tab] array */ @@ -93,6 +97,7 @@ sealed class Tab(open val mode: MusicMode) { /** * Convert a [Tab] integer representation into it's corresponding array of [Tab]s. + * * @param intCode The integer representation of the [Tab]s. * @return An array of [Tab]s corresponding to the sequence. */ diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt index c60084cf9..d04a190fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.inflater /** * A [RecyclerView.Adapter] that displays an array of [Tab]s open for configuration. + * * @param listener A [EditableListListener] for tab interactions. */ class TabAdapter(private val listener: EditableListListener) : @@ -46,6 +47,7 @@ class TabAdapter(private val listener: EditableListListener) : /** * Immediately update the tab array. This should be used when initializing the list. + * * @param newTabs The new array of tabs to show. */ fun submitTabs(newTabs: Array) { @@ -55,6 +57,7 @@ class TabAdapter(private val listener: EditableListListener) : /** * Update a specific tab to the given value. + * * @param at The position of the tab to update. * @param tab The new tab. */ @@ -66,6 +69,7 @@ class TabAdapter(private val listener: EditableListListener) : /** * Swap two tabs with each other. + * * @param a The position of the first tab to swap. * @param b The position of the second tab to swap. */ @@ -83,12 +87,14 @@ class TabAdapter(private val listener: EditableListListener) : /** * A [RecyclerView.ViewHolder] that displays a [Tab]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class TabViewHolder private constructor(private val binding: ItemTabBinding) : DialogRecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param tab The new [Tab] to bind. * @param listener A [EditableListListener] to bind interactions to. */ @@ -114,6 +120,7 @@ class TabViewHolder private constructor(private val binding: ItemTabBinding) : companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt index 516a54257..0ea7d4586 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabCustomizeDialog.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.util.logD /** * A [ViewBindingDialogFragment] that allows the user to modify the home [Tab] configuration. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabDragCallback.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabDragCallback.kt index 0eeb29b1e..b64a4f1b5 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabDragCallback.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabDragCallback.kt @@ -23,6 +23,7 @@ import androidx.recyclerview.widget.RecyclerView /** * An [ItemTouchHelper.Callback] that implements dragging in the [TabAdapter]. + * * @author Alexander Capehart (OxygenCobalt) */ class TabDragCallback(private val adapter: TabAdapter) : ItemTouchHelper.Callback() { diff --git a/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt index 70a4a912b..8bc1d2aee 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt @@ -55,14 +55,16 @@ constructor( interface Target { /** * Configure the [ImageRequest.Builder] to enable [Target]-specific configuration. + * * @param builder The [ImageRequest.Builder] that will be used to request the desired - * [Bitmap]. + * [Bitmap]. * @return The same [ImageRequest.Builder] in order to easily chain configuration methods. */ fun onConfigRequest(builder: ImageRequest.Builder): ImageRequest.Builder = builder /** * Called when the loading process is completed. + * * @param bitmap The loaded bitmap, or null if the bitmap could not be loaded. */ fun onCompleted(bitmap: Bitmap?) @@ -77,6 +79,7 @@ constructor( /** * Load the Album cover [Bitmap] from a [Song]. + * * @param song The song to load a [Bitmap] of it's album cover from. * @param target The [Target] to deliver the [Bitmap] to asynchronously. */ diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt index d1a656f4c..db34dceb6 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt @@ -21,6 +21,7 @@ import org.oxycblt.auxio.IntegerTable /** * Represents the options available for album cover loading. + * * @author Alexander Capehart (OxygenCobalt) */ enum class CoverMode { @@ -33,6 +34,7 @@ enum class CoverMode { /** * The integer representation of this instance. + * * @see fromIntCode */ val intCode: Int @@ -46,6 +48,7 @@ enum class CoverMode { companion object { /** * Convert a [CoverMode] integer representation into an instance. + * * @param intCode An integer representation of a [CoverMode] * @return The corresponding [CoverMode], or null if the [CoverMode] is invalid. * @see CoverMode.intCode diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt index 68adab079..25eaa4458 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt @@ -48,9 +48,9 @@ import org.oxycblt.auxio.util.getInteger * This class is primarily intended for list items. For other uses, [StyledImageView] is more * suitable. * - * TODO: Rework content descriptions here - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Rework content descriptions here */ class ImageGroup @JvmOverloads @@ -146,6 +146,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Bind a [Song] to the internal [StyledImageView]. + * * @param song The [Song] to bind to the view. * @see StyledImageView.bind */ @@ -153,6 +154,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Bind a [Album] to the internal [StyledImageView]. + * * @param album The [Album] to bind to the view. * @see StyledImageView.bind */ @@ -160,6 +162,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Bind a [Genre] to the internal [StyledImageView]. + * * @param artist The [Artist] to bind to the view. * @see StyledImageView.bind */ @@ -167,6 +170,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Bind a [Genre] to the internal [StyledImageView]. + * * @param genre The [Genre] to bind to the view. * @see StyledImageView.bind */ diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt index 866cdca2f..e6d321a87 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.util.logD /** * User configuration specific to image loading. + * * @author Alexander Capehart (OxygenCobalt) */ interface ImageSettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt b/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt index 61e197263..5405a1f51 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt @@ -48,11 +48,10 @@ import org.oxycblt.auxio.util.getDrawableCompat /** * An [AppCompatImageView] with some additional styling, including: - * * - Tonal background * - Rounded corners based on user preferences * - Built-in support for binding image data or using a static icon with the same styling as - * placeholder drawables. + * placeholder drawables. * * @author Alexander Capehart (OxygenCobalt) */ @@ -97,34 +96,39 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Bind a [Song]'s album cover to this view, also updating the content description. + * * @param song The [Song] to bind. */ fun bind(song: Song) = bindImpl(song, R.drawable.ic_song_24, R.string.desc_album_cover) /** * Bind an [Album]'s cover to this view, also updating the content description. + * * @param album the [Album] to bind. */ fun bind(album: Album) = bindImpl(album, R.drawable.ic_album_24, R.string.desc_album_cover) /** * Bind an [Artist]'s image to this view, also updating the content description. + * * @param artist the [Artist] to bind. */ fun bind(artist: Artist) = bindImpl(artist, R.drawable.ic_artist_24, R.string.desc_artist_image) /** * Bind an [Genre]'s image to this view, also updating the content description. + * * @param genre the [Genre] to bind. */ fun bind(genre: Genre) = bindImpl(genre, R.drawable.ic_genre_24, R.string.desc_genre_image) /** * Internally bind a [Music]'s image to this view. + * * @param music The music to find. * @param errorRes The error drawable resource to use if the music cannot be loaded. * @param descRes The content description string resource to use. The resource must have one - * field for the name of the [Music]. + * field for the name of the [Music]. */ private fun bindImpl(music: Music, @DrawableRes errorRes: Int, @StringRes descRes: Int) { val request = @@ -144,6 +148,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * A [Drawable] wrapper that re-styles the drawable to better align with the style of * [StyledImageView]. + * * @param context [Context] required for initialization. * @param inner The [Drawable] to wrap. */ diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt index 64c9a948a..38ad9dc59 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt @@ -41,6 +41,7 @@ import org.oxycblt.auxio.music.Song /** * A [Keyer] implementation for [Music] data. + * * @author Alexander Capehart (OxygenCobalt) */ class MusicKeyer : Keyer { @@ -56,6 +57,7 @@ class MusicKeyer : Keyer { /** * Generic [Fetcher] for [Album] covers. Works with both [Album] and [Song]. Use [SongFactory] or * [AlbumFactory] for instantiation. + * * @author Alexander Capehart (OxygenCobalt) */ class AlbumCoverFetcher @@ -89,6 +91,7 @@ private constructor( /** * [Fetcher] for [Artist] images. Use [Factory] for instantiation. + * * @author Alexander Capehart (OxygenCobalt) */ class ArtistImageFetcher @@ -116,6 +119,7 @@ private constructor( /** * [Fetcher] for [Genre] images. Use [Factory] for instantiation. + * * @author Alexander Capehart (OxygenCobalt) */ class GenreImageFetcher @@ -141,9 +145,10 @@ private constructor( /** * Map at most N [T] items a collection into a collection of [R], ignoring [T] that cannot be * transformed into [R]. + * * @param n The maximum amount of items to map. * @param transform The function that transforms data [T] from the original list into data [R] in - * the new list. Can return null if the [T] cannot be transformed into an [R]. + * the new list. Can return null if the [T] cannot be transformed into an [R]. * @return A new list of at most N non-null [R] items. */ private inline fun Collection.mapAtMostNotNull( diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/Covers.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Covers.kt index 16b14f1a1..d92924320 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/Covers.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Covers.kt @@ -38,16 +38,18 @@ import org.oxycblt.auxio.util.logW /** * Internal utilities for loading album covers. + * * @author Alexander Capehart (OxygenCobalt). */ object Covers { /** * Fetch an album cover, respecting the current cover configuration. + * * @param context [Context] required to load the image. * @param imageSettings [ImageSettings] required to obtain configuration information. * @param album [Album] to load the cover from. * @return An [InputStream] of image data if the cover loading was successful, null if the cover - * loading failed or should not occur. + * loading failed or should not occur. */ suspend fun fetch(context: Context, imageSettings: ImageSettings, album: Album): InputStream? { return try { @@ -67,7 +69,7 @@ object Covers { * order: * - [MediaMetadataRetriever], as it has the best support and speed. * - ExoPlayer's [MetadataRetriever], as some devices (notably Samsung) can have broken - * [MediaMetadataRetriever] implementations. + * [MediaMetadataRetriever] implementations. * - MediaStore, as a last-ditch fallback if the format is really obscure. * * @param context [Context] required to load the image. @@ -80,6 +82,7 @@ object Covers { /** * Loads an album cover with [MediaMetadataRetriever]. + * * @param context [Context] required to load the image. * @param album [Album] to load the cover from. * @return An [InputStream] of image data if the cover loading was successful, null otherwise. @@ -99,6 +102,7 @@ object Covers { /** * Loads an [Album] cover with ExoPlayer's [MetadataRetriever]. + * * @param context [Context] required to load the image. * @param album [Album] to load the cover from. * @return An [InputStream] of image data if the cover loading was successful, null otherwise. @@ -173,6 +177,7 @@ object Covers { /** * Loads an [Album] cover from MediaStore. + * * @param context [Context] required to load the image. * @param album [Album] to load the cover from. * @return An [InputStream] of image data if the cover loading was successful, null otherwise. diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/ErrorCrossfadeTransitionFactory.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/ErrorCrossfadeTransitionFactory.kt index 676cc53bb..2d577f354 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/ErrorCrossfadeTransitionFactory.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/ErrorCrossfadeTransitionFactory.kt @@ -27,6 +27,7 @@ import coil.transition.TransitionTarget /** * A copy of [CrossfadeTransition.Factory] that also applies a transition to error results. + * * @author Coil Team, Alexander Capehart (OxygenCobalt) */ class ErrorCrossfadeTransitionFactory : Transition.Factory { diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/Images.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Images.kt index df9f4ba19..24c85c53c 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/Images.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Images.kt @@ -37,12 +37,14 @@ import okio.source /** * Utilities for constructing Artist and Genre images. + * * @author Alexander Capehart (OxygenCobalt), Karim Abou Zeid */ object Images { /** * Create a mosaic image from the given image [InputStream]s. Derived from phonograph: * https://github.com/kabouzeid/Phonograph + * * @param context [Context] required to generate the mosaic. * @param streams [InputStream]s of image data to create the mosaic out of. * @param size [Size] of the Mosaic to generate. @@ -104,8 +106,9 @@ object Images { /** * Get an image dimension suitable to create a mosaic with. + * * @return A pixel dimension derived from the given [Dimension] that will always be even, - * allowing it to be sub-divided. + * allowing it to be sub-divided. */ private fun Dimension.mosaicSize(): Int { val size = pxOrElse { 512 } diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt index 1e31a237e..7dd638fd3 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt @@ -26,6 +26,7 @@ import kotlin.math.min /** * A transformation that performs a center crop-style transformation on an image. Allowing this * behavior to be intrinsic without any view configuration. + * * @author Alexander Capehart (OxygenCobalt) */ class SquareFrameTransform : Transformation { diff --git a/app/src/main/java/org/oxycblt/auxio/list/Data.kt b/app/src/main/java/org/oxycblt/auxio/list/Data.kt index e77d0afb4..297042f7e 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Data.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Data.kt @@ -24,6 +24,7 @@ interface Item /** * A "header" used for delimiting groups of data. + * * @author Alexander Capehart (OxygenCobalt) */ interface Header : Item { @@ -33,6 +34,7 @@ interface Header : Item { /** * A basic header with no additional actions. + * * @param titleRes The string resource used for the header's title. * @author Alexander Capehart (OxygenCobalt) */ diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt index 2363fc059..9eb8704ca 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt @@ -36,6 +36,7 @@ import org.oxycblt.auxio.util.showToast /** * A Fragment containing a selectable list. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class ListFragment : @@ -52,6 +53,7 @@ abstract class ListFragment : /** * Called when [onClick] is called, but does not result in the item being selected. This more or * less corresponds to an [onClick] implementation in a non-[ListFragment]. + * * @param item The [T] data of the item that was clicked. */ abstract fun onRealClick(item: T) @@ -73,6 +75,7 @@ abstract class ListFragment : /** * Opens a menu in the context of a [Song]. This menu will be managed by the Fragment and closed * when the view is destroyed. If a menu is already opened, this call is ignored. + * * @param anchor The [View] to anchor the menu to. * @param menuRes The resource of the menu to load. * @param song The [Song] to create the menu for. @@ -111,6 +114,7 @@ abstract class ListFragment : /** * Opens a menu in the context of a [Album]. This menu will be managed by the Fragment and * closed when the view is destroyed. If a menu is already opened, this call is ignored. + * * @param anchor The [View] to anchor the menu to. * @param menuRes The resource of the menu to load. * @param album The [Album] to create the menu for. @@ -147,6 +151,7 @@ abstract class ListFragment : /** * Opens a menu in the context of a [Artist]. This menu will be managed by the Fragment and * closed when the view is destroyed. If a menu is already opened, this call is ignored. + * * @param anchor The [View] to anchor the menu to. * @param menuRes The resource of the menu to load. * @param artist The [Artist] to create the menu for. @@ -180,6 +185,7 @@ abstract class ListFragment : /** * Opens a menu in the context of a [Genre]. This menu will be managed by the Fragment and * closed when the view is destroyed. If a menu is already opened, this call is ignored. + * * @param anchor The [View] to anchor the menu to. * @param menuRes The resource of the menu to load. * @param genre The [Genre] to create the menu for. @@ -226,6 +232,7 @@ abstract class ListFragment : /** * Open a menu. This menu will be managed by the Fragment and closed when the view is destroyed. * If a menu is already opened, this call is ignored. + * * @param anchor The [View] to anchor the menu to. * @param menuRes The resource of the menu to load. * @param block A block that is ran within [PopupMenu] that allows further configuration. diff --git a/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt b/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt index 1afa340c3..dd0f3d780 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Listeners.kt @@ -23,11 +23,13 @@ import androidx.recyclerview.widget.RecyclerView /** * A basic listener for list interactions. + * * @author Alexander Capehart (OxygenCobalt) */ interface ClickableListListener { /** * Called when an item in the list is clicked. + * * @param item The [T] item that was clicked. * @param viewHolder The [RecyclerView.ViewHolder] of the item that was clicked. */ @@ -35,10 +37,11 @@ interface ClickableListListener { /** * Binds this instance to a list item. + * * @param item The [T] to bind this item to. * @param viewHolder The [RecyclerView.ViewHolder] of the item that was clicked. * @param bodyView The [View] containing the main body of the list item. Any click events on - * this [View] are routed to the listener. Defaults to the root view. + * this [View] are routed to the listener. Defaults to the root view. */ fun bind(item: T, viewHolder: RecyclerView.ViewHolder, bodyView: View = viewHolder.itemView) { bodyView.setOnClickListener { onClick(item, viewHolder) } @@ -47,21 +50,24 @@ interface ClickableListListener { /** * An extension of [ClickableListListener] that enables list editing functionality. + * * @author Alexander Capehart (OxygenCobalt) */ interface EditableListListener : ClickableListListener { /** * Called when a [RecyclerView.ViewHolder] requests that it should be dragged. + * * @param viewHolder The [RecyclerView.ViewHolder] that should start being dragged. */ fun onPickUp(viewHolder: RecyclerView.ViewHolder) /** * Binds this instance to a list item. + * * @param item The [T] to bind this item to. * @param viewHolder The [RecyclerView.ViewHolder] to bind. * @param bodyView The [View] containing the main body of the list item. Any click events on - * this [View] are routed to the listener. Defaults to the root view. + * this [View] are routed to the listener. Defaults to the root view. * @param dragHandle A touchable [View]. Any drag on this view will start a drag event. */ fun bind( @@ -83,11 +89,13 @@ interface EditableListListener : ClickableListListener { /** * An extension of [ClickableListListener] that enables menu and selection functionality. + * * @author Alexander Capehart (OxygenCobalt) */ interface SelectableListListener : ClickableListListener { /** * Called when an item in the list requests that a menu related to it should be opened. + * * @param item The [T] item to open a menu for. * @param anchor The [View] to anchor the menu to. */ @@ -95,16 +103,18 @@ interface SelectableListListener : ClickableListListener { /** * Called when an item in the list requests that it be selected. + * * @param item The [T] item to select. */ fun onSelect(item: T) /** * Binds this instance to a list item. + * * @param item The [T] to bind this item to. * @param viewHolder The [RecyclerView.ViewHolder] to bind. * @param bodyView The [View] containing the main body of the list item. Any click events on - * this [View] are routed to the listener. Defaults to the root view. + * this [View] are routed to the listener. Defaults to the root view. * @param menuButton A clickable [View]. Any click events on this [View] will open a menu. */ fun bind( diff --git a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt index 941d7ffc5..cd64d98e8 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt @@ -38,6 +38,7 @@ import org.oxycblt.auxio.music.metadata.Disc data class Sort(val mode: Mode, val direction: Direction) { /** * Create a new [Sort] with the same [mode], but a different [Direction]. + * * @param direction The new [Direction] to sort in. * @return A new sort with the same mode, but with the new [Direction] value applied. */ @@ -45,6 +46,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Create a new [Sort] with the same [direction] value, but different [mode] value. + * * @param mode Tbe new mode to use for the Sort. * @return A new sort with the same [direction] value, but with the new [mode] applied. */ @@ -52,6 +54,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a list of [Song]s. + * * @param songs The list of [Song]s. * @return A new list of [Song]s sorted by this [Sort]'s configuration. */ @@ -63,6 +66,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a list of [Album]s. + * * @param albums The list of [Album]s. * @return A new list of [Album]s sorted by this [Sort]'s configuration. */ @@ -74,6 +78,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a list of [Artist]s. + * * @param artists The list of [Artist]s. * @return A new list of [Artist]s sorted by this [Sort]'s configuration. */ @@ -85,6 +90,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a list of [Genre]s. + * * @param genres The list of [Genre]s. * @return A new list of [Genre]s sorted by this [Sort]'s configuration. */ @@ -96,6 +102,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a *mutable* list of [Song]s in-place using this [Sort]'s configuration. + * * @param songs The [Song]s to sort. */ private fun songsInPlace(songs: MutableList) { @@ -104,6 +111,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a *mutable* list of [Album]s in-place using this [Sort]'s configuration. + * * @param albums The [Album]s to sort. */ private fun albumsInPlace(albums: MutableList) { @@ -112,6 +120,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a *mutable* list of [Artist]s in-place using this [Sort]'s configuration. + * * @param artists The [Album]s to sort. */ private fun artistsInPlace(artists: MutableList) { @@ -120,6 +129,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort a *mutable* list of [Genre]s in-place using this [Sort]'s configuration. + * * @param genres The [Genre]s to sort. */ private fun genresInPlace(genres: MutableList) { @@ -128,6 +138,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * The integer representation of this instance. + * * @see fromIntCode */ val intCode: Int @@ -150,6 +161,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Get a [Comparator] that sorts [Song]s according to this [Mode]. + * * @param direction The direction to sort in. * @return A [Comparator] that can be used to sort a [Song] list according to this [Mode]. */ @@ -159,6 +171,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Get a [Comparator] that sorts [Album]s according to this [Mode]. + * * @param direction The direction to sort in. * @return A [Comparator] that can be used to sort a [Album] list according to this [Mode]. */ @@ -168,6 +181,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Return a [Comparator] that sorts [Artist]s according to this [Mode]. + * * @param direction The direction to sort in. * @return A [Comparator] that can be used to sort a [Artist] list according to this [Mode]. */ @@ -177,6 +191,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Return a [Comparator] that sorts [Genre]s according to this [Mode]. + * * @param direction The direction to sort in. * @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode]. */ @@ -186,6 +201,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the item's name. + * * @see Music.collationKey */ object ByName : Mode() { @@ -210,6 +226,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the [Album] of an item. Only available for [Song]s. + * * @see Album.collationKey */ object ByAlbum : Mode() { @@ -229,6 +246,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the [Artist] name of an item. Only available for [Song] and [Album]. + * * @see Artist.collationKey */ object ByArtist : Mode() { @@ -256,6 +274,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the [Date] of an item. Only available for [Song] and [Album]. + * * @see Song.date * @see Album.dates */ @@ -308,6 +327,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the amount of songs an item contains. Only available for [MusicParent]s. + * * @see MusicParent.songs */ object ByCount : Mode() { @@ -333,6 +353,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the disc number of an item. Only available for [Song]s. + * * @see Song.disc */ object ByDisc : Mode() { @@ -351,6 +372,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the track number of an item. Only available for [Song]s. + * * @see Song.track */ object ByTrack : Mode() { @@ -369,6 +391,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the date an item was added. Only supported by [Song]s and [Album]s. + * * @see Song.dateAdded * @see Album.dates */ @@ -391,6 +414,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Utility function to create a [Comparator] in a dynamic way determined by [direction]. + * * @param direction The [Direction] to sort in. * @see compareBy * @see compareByDescending @@ -406,6 +430,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Utility function to create a [Comparator] in a dynamic way determined by [direction] + * * @param direction The [Direction] to sort in. * @param comparator A [Comparator] to wrap. * @return A new [Comparator] with the specified configuration. @@ -419,6 +444,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Utility function to create a [Comparator] a dynamic way determined by [direction] + * * @param direction The [Direction] to sort in. * @param comparator A [Comparator] to wrap. * @param selector Called to obtain a specific attribute to sort by. @@ -439,6 +465,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Utility function to create a [Comparator] that sorts in ascending order based on the * given [Comparator], with a selector based on the item itself. + * * @param comparator The [Comparator] to wrap. * @return A new [Comparator] with the specified configuration. * @see compareBy @@ -448,8 +475,9 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * A [Comparator] that chains several other [Comparator]s together to form one comparison. + * * @param comparators The [Comparator]s to chain. These will be iterated through in order - * during a comparison, with the first non-equal result becoming the result. + * during a comparison, with the first non-equal result becoming the result. */ private class MultiComparator(vararg comparators: Comparator) : Comparator { private val _comparators = comparators @@ -468,6 +496,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Wraps a [Comparator], extending it to compare two lists. + * * @param inner The [Comparator] to use. */ private class ListComparator(private val inner: Comparator) : Comparator> { @@ -500,6 +529,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * A [Comparator] that compares abstract [Music] values. Internally, this is similar to * [NullableComparator], however comparing [Music.collationKey] instead of [Comparable]. + * * @see NullableComparator * @see Music.collationKey */ @@ -555,6 +585,7 @@ data class Sort(val mode: Mode, val direction: Direction) { companion object { /** * Convert a [Mode] integer representation into an instance. + * * @param intCode An integer representation of a [Mode] * @return The corresponding [Mode], or null if the [Mode] is invalid. * @see intCode @@ -575,6 +606,7 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Convert a menu item ID into a [Mode]. + * * @param itemId The menu resource ID to convert * @return A [Mode] corresponding to the given ID, or null if the ID is invalid. * @see itemId @@ -604,6 +636,7 @@ data class Sort(val mode: Mode, val direction: Direction) { companion object { /** * Convert a [Sort] integer representation into an instance. + * * @param intCode An integer representation of a [Sort] * @return The corresponding [Sort], or null if the [Sort] is invalid. * @see intCode diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/DiffAdapter.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/DiffAdapter.kt index 23e49344d..cbedc49b7 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/DiffAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/DiffAdapter.kt @@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView /** * A [RecyclerView.Adapter] with [ListDiffer] integration. + * * @param differFactory The [ListDiffer.Factory] that defines the type of [ListDiffer] to use. */ abstract class DiffAdapter( @@ -36,6 +37,7 @@ abstract class DiffAdapter( /** * Get a [T] item at the given position. + * * @param at The position to get the item at. * @throws IndexOutOfBoundsException If the index is not in the list bounds/ */ @@ -43,6 +45,7 @@ abstract class DiffAdapter( /** * Dynamically determine how to update the list based on the given instructions. + * * @param newList The new list of [T] items to show. * @param instructions The instructions specifying how to update the list. * @param onDone Called when the update process is completed. Defaults to a no-op. diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/ListDiffer.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/ListDiffer.kt index 7c5207e6c..1a0851ee8 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/ListDiffer.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/ListDiffer.kt @@ -28,6 +28,7 @@ import androidx.recyclerview.widget.RecyclerView /** * List differ wrapper that provides more flexibility regarding the way lists are updated. + * * @author Alexander Capehart (OxygenCobalt) */ interface ListDiffer { @@ -36,6 +37,7 @@ interface ListDiffer { /** * Dynamically determine how to update the list based on the given instructions. + * * @param newList The new list of [T] items to show. * @param instructions The [BasicListInstructions] specifying how to update the list. * @param onDone Called when the update process is completed. @@ -49,6 +51,7 @@ interface ListDiffer { abstract class Factory { /** * Create a new [ListDiffer] bound to the given [RecyclerView.Adapter]. + * * @param adapter The [RecyclerView.Adapter] to bind to. */ abstract fun new(adapter: RecyclerView.Adapter<*>): ListDiffer @@ -57,8 +60,9 @@ interface ListDiffer { /** * Update lists on another thread. This is useful when large diffs are likely to occur in this * list that would be exceedingly slow with [Blocking]. + * * @param diffCallback A [DiffUtil.ItemCallback] to use for item comparison when diffing the - * internal list. + * internal list. */ class Async(private val diffCallback: DiffUtil.ItemCallback) : Factory() { @@ -69,8 +73,9 @@ interface ListDiffer { /** * Update lists on the main thread. This is useful when many small, discrete list diffs are * likely to occur that would cause [Async] to suffer from race conditions. + * * @param diffCallback A [DiffUtil.ItemCallback] to use for item comparison when diffing the - * internal list. + * internal list. */ class Blocking(private val diffCallback: DiffUtil.ItemCallback) : Factory() { @@ -81,6 +86,7 @@ interface ListDiffer { /** * Represents the specific way to update a list of items. + * * @author Alexander Capehart (OxygenCobalt) */ enum class BasicListInstructions { diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/PlayingIndicatorAdapter.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/PlayingIndicatorAdapter.kt index 588c5c9b6..b4a66d000 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/PlayingIndicatorAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/PlayingIndicatorAdapter.kt @@ -23,6 +23,7 @@ import org.oxycblt.auxio.util.logD /** * A [RecyclerView.Adapter] that supports indicating the playback status of a particular item. + * * @param differFactory The [ListDiffer.Factory] that defines the type of [ListDiffer] to use. * @author Alexander Capehart (OxygenCobalt) */ @@ -50,6 +51,7 @@ abstract class PlayingIndicatorAdapter( } /** * Update the currently playing item in the list. + * * @param item The [T] currently being played, or null if it is not being played. * @param isPlaying Whether playback is ongoing or paused. */ @@ -103,9 +105,10 @@ abstract class PlayingIndicatorAdapter( abstract class ViewHolder(root: View) : RecyclerView.ViewHolder(root) { /** * Update the playing indicator within this [RecyclerView.ViewHolder]. + * * @param isActive True if this item is playing, false otherwise. * @param isPlaying True if playback is ongoing, false if paused. If this is true, - * [isActive] will also be true. + * [isActive] will also be true. */ abstract fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) } diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/SelectionIndicatorAdapter.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/SelectionIndicatorAdapter.kt index 20239546c..30e15468e 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/SelectionIndicatorAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/SelectionIndicatorAdapter.kt @@ -24,6 +24,7 @@ import org.oxycblt.auxio.music.Music /** * A [PlayingIndicatorAdapter] that also supports indicating the selection status of a group of * items. + * * @param differFactory The [ListDiffer.Factory] that defines the type of [ListDiffer] to use. * @author Alexander Capehart (OxygenCobalt) */ @@ -41,6 +42,7 @@ abstract class SelectionIndicatorAdapter( /** * Update the list of selected items. + * * @param items A set of selected [T] items. */ fun setSelected(items: Set) { @@ -74,6 +76,7 @@ abstract class SelectionIndicatorAdapter( abstract class ViewHolder(root: View) : PlayingIndicatorAdapter.ViewHolder(root) { /** * Update the selection indicator within this [PlayingIndicatorAdapter.ViewHolder]. + * * @param isSelected Whether this [PlayingIndicatorAdapter.ViewHolder] is selected. */ abstract fun updateSelectionIndicator(isSelected: Boolean) diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/SimpleDiffCallback.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/SimpleDiffCallback.kt index 358c3b3f1..89d95a35e 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/SimpleDiffCallback.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/SimpleDiffCallback.kt @@ -23,6 +23,7 @@ import org.oxycblt.auxio.list.Item /** * A [DiffUtil.ItemCallback] that automatically implements the [areItemsTheSame] method. Use this * whenever creating [DiffUtil.ItemCallback] implementations with an [Item] subclass. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class SimpleDiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/AuxioRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/AuxioRecyclerView.kt index 06eea4411..18fa62394 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/AuxioRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/AuxioRecyclerView.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat * - Automatic edge-to-edge support * - Adapter-based [SpanSizeLookup] implementation * - Automatic [setHasFixedSize] setup + * * @author Alexander Capehart (OxygenCobalt) */ open class AuxioRecyclerView @@ -89,6 +90,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr interface SpanSizeLookup { /** * Get if the item at a position takes up the whole width of the [RecyclerView] or not. + * * @param position The position of the item. * @return true if the item is full-width, false otherwise. */ diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/DialogRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/DialogRecyclerView.kt index 6984f1c93..313670ece 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/DialogRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/DialogRecyclerView.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.util.getDimenPixels * A [RecyclerView] intended for use in Dialogs, adding features such as: * - NestedScrollView scrollIndicators behavior emulation * - Dialog-specific [ViewHolder] that automatically resolves certain issues. + * * @author Alexander Capehart (OxygenCobalt) */ class DialogRecyclerView diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/HeaderItemDecoration.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/HeaderItemDecoration.kt index b715b8b70..831b8aff4 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/HeaderItemDecoration.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/HeaderItemDecoration.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.list.adapter.DiffAdapter /** * A [BackportMaterialDividerItemDecoration] that sets up the divider configuration to correctly * separate content with headers. + * * @author Alexander Capehart (OxygenCobalt) */ class HeaderItemDecoration diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt index ff09af8b1..a683fca2b 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt @@ -36,12 +36,14 @@ import org.oxycblt.auxio.util.logD /** * A [RecyclerView.ViewHolder] that displays a [Song]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class SongViewHolder private constructor(private val binding: ItemSongBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param song The new [Song] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -67,6 +69,7 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -84,12 +87,14 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : /** * A [RecyclerView.ViewHolder] that displays a [Album]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class AlbumViewHolder private constructor(private val binding: ItemParentBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param album The new [Album] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -115,6 +120,7 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -133,12 +139,14 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding /** * A [RecyclerView.ViewHolder] that displays a [Artist]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class ArtistViewHolder private constructor(private val binding: ItemParentBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param artist The new [Artist] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -173,6 +181,7 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -192,12 +201,14 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin /** * A [RecyclerView.ViewHolder] that displays a [Genre]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class GenreViewHolder private constructor(private val binding: ItemParentBinding) : SelectionIndicatorAdapter.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param genre The new [Genre] to bind. * @param listener An [SelectableListListener] to bind interactions to. */ @@ -227,6 +238,7 @@ class GenreViewHolder private constructor(private val binding: ItemParentBinding /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ @@ -243,12 +255,14 @@ class GenreViewHolder private constructor(private val binding: ItemParentBinding /** * A [RecyclerView.ViewHolder] that displays a [BasicHeader]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class BasicHeaderViewHolder private constructor(private val binding: ItemHeaderBinding) : RecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param basicHeader The new [BasicHeader] to bind. */ fun bind(basicHeader: BasicHeader) { @@ -262,6 +276,7 @@ class BasicHeaderViewHolder private constructor(private val binding: ItemHeaderB /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt index b9912bc09..fecc082ce 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.util.showToast /** * A subset of ListFragment that implements aspects of the selection UI. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class SelectionFragment : @@ -38,8 +39,9 @@ abstract class SelectionFragment : /** * Get the [SelectionToolbarOverlay] of the concrete Fragment to be automatically managed by * [SelectionFragment]. + * * @return The [SelectionToolbarOverlay] of the concrete [SelectionFragment]'s [VB], or null if - * there is not one. + * there is not one. */ open fun getSelectionToolbar(binding: VB): SelectionToolbarOverlay? = null diff --git a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionToolbarOverlay.kt b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionToolbarOverlay.kt index 106244edd..664cfaaae 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionToolbarOverlay.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionToolbarOverlay.kt @@ -32,6 +32,7 @@ import org.oxycblt.auxio.util.logD /** * A wrapper around a [MaterialToolbar] that adds an additional [MaterialToolbar] showing the * current selection state. + * * @author Alexander Capehart (OxygenCobalt) */ class SelectionToolbarOverlay @@ -65,6 +66,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Set an OnClickListener for when the "cancel" button in the selection [MaterialToolbar] is * pressed. + * * @param listener The OnClickListener to respond to this interaction. * @see MaterialToolbar.setNavigationOnClickListener */ @@ -75,6 +77,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Set an [OnMenuItemClickListener] for when a MenuItem is selected from the selection * [MaterialToolbar]. + * * @param listener The [OnMenuItemClickListener] to respond to this interaction. * @see MaterialToolbar.setOnMenuItemClickListener */ @@ -84,6 +87,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Update the selection [MaterialToolbar] to reflect the current selection amount. + * * @param amount The amount of items that are currently selected. * @return true if the selection [MaterialToolbar] changes, false otherwise. */ @@ -101,6 +105,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Animate the visibility of the inner and selection [MaterialToolbar]s to the given state. + * * @param selectionVisible Whether the selection [MaterialToolbar] should be visible or not. * @return true if the toolbars have changed, false otherwise. */ @@ -152,8 +157,9 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr /** * Update the alpha of the inner and selection [MaterialToolbar]s. + * * @param innerAlpha The opacity of the inner [MaterialToolbar]. This will map to the inverse - * opacity of the selection [MaterialToolbar]. + * opacity of the selection [MaterialToolbar]. */ private fun setToolbarsAlpha(innerAlpha: Float) { innerToolbar.apply { diff --git a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionViewModel.kt b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionViewModel.kt index 66424b1d1..ea08ea56b 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionViewModel.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.music.model.Library /** * A [ViewModel] that manages the current selection. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -67,6 +68,7 @@ class SelectionViewModel @Inject constructor(private val musicRepository: MusicR /** * Select a new [Music] item. If this item is already within the selected items, the item will * be removed. Otherwise, it will be added. + * * @param music The [Music] item to select. */ fun select(music: Music) { @@ -79,6 +81,7 @@ class SelectionViewModel @Inject constructor(private val musicRepository: MusicR /** * Consume the current selection. This will clear any items that were selected prior. + * * @return The list of selected items before it was cleared. */ fun consume() = _selected.value.also { _selected.value = listOf() } diff --git a/app/src/main/java/org/oxycblt/auxio/music/AudioOnlyExtractors.kt b/app/src/main/java/org/oxycblt/auxio/music/AudioOnlyExtractors.kt index 75eb1bdd1..3220e8ef9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/AudioOnlyExtractors.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/AudioOnlyExtractors.kt @@ -28,6 +28,7 @@ import com.google.android.exoplayer2.extractor.wav.WavExtractor /** * A [ExtractorsFactory] that only provides audio containers to save APK space. + * * @author Alexander Capehart (OxygenCobalt) */ object AudioOnlyExtractors : ExtractorsFactory { 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 665010655..10fe9f0d6 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -38,11 +38,13 @@ import org.oxycblt.auxio.util.toUuidOrNull /** * Abstract music data. This contains universal information about all concrete music * implementations, such as identification information and names. + * * @author Alexander Capehart (OxygenCobalt) */ sealed interface Music : Item { /** * A unique identifier for this music item. + * * @see UID */ val uid: UID @@ -56,9 +58,10 @@ sealed interface Music : Item { /** * Returns a name suitable for use in the app UI. This should be favored over [rawName] in * nearly all cases. + * * @param context [Context] required to obtain placeholder text or formatting information. * @return A human-readable string representing the name of this music. In the case that the - * item does not have a name, an analogous "Unknown X" name is returned. + * item does not have a name, an analogous "Unknown X" name is returned. */ fun resolveName(context: Context): String @@ -76,7 +79,7 @@ sealed interface Music : Item { * The key will have the following attributes: * - If [rawSortName] is present, this key will be derived from it. Otherwise [rawName] is used. * - If the string begins with an article, such as "the", it will be stripped, as is usually - * convention for sorting media. This is not internationalized. + * convention for sorting media. This is not internationalized. */ val collationKey: CollationKey? @@ -86,15 +89,14 @@ sealed interface Music : Item { * [UID] enables a much cheaper and more reliable form of differentiating music, derived from * either a hash of meaningful metadata or the MusicBrainz ID spec. Using this enables several * improvements to music management in this app, including: - * * - Proper differentiation of identical music. It's common for large, well-tagged libraries to - * have functionally duplicate items that are differentiated with MusicBrainz IDs, and so [UID] - * allows us to properly differentiate between these in the app. + * have functionally duplicate items that are differentiated with MusicBrainz IDs, and so + * [UID] allows us to properly differentiate between these in the app. * - Better music persistence between restarts. Whereas directly storing song names would be - * prone to collisions, and storing MediaStore IDs would drift rapidly as the music library - * changes, [UID] enables a much stronger form of persistence given it's unique link to a - * specific files metadata configuration, which is unlikely to collide with another item or - * drift as the music library changes. + * prone to collisions, and storing MediaStore IDs would drift rapidly as the music library + * changes, [UID] enables a much stronger form of persistence given it's unique link to a + * specific files metadata configuration, which is unlikely to collide with another item or + * drift as the music library changes. * * Note: Generally try to use [UID] as a black box that can only be read, written, and compared. * It will not be fun if you try to manipulate it in any other manner. @@ -125,6 +127,7 @@ sealed interface Music : Item { /** * Internal marker of [Music.UID] format type. + * * @param namespace Namespace to use in the [Music.UID]'s string representation. */ private enum class Format(val namespace: String) { @@ -139,10 +142,11 @@ sealed interface Music : Item { /** * Creates an Auxio-style [UID] with a [UUID] composed of a hash of the non-subjective, * unlikely-to-change metadata of the music. + * * @param mode The analogous [MusicMode] of the item that created this [UID]. * @param updates Block to update the [MessageDigest] hash with the metadata of the - * item. Make sure the metadata hashed semantically aligns with the format - * specification. + * item. Make sure the metadata hashed semantically aligns with the format + * specification. * @return A new auxio-style [UID]. */ fun auxio(mode: MusicMode, updates: MessageDigest.() -> Unit): UID { @@ -181,19 +185,21 @@ sealed interface Music : Item { /** * Creates a MusicBrainz-style [UID] with a [UUID] derived from the MusicBrainz ID * extracted from a file. + * * @param mode The analogous [MusicMode] of the item that created this [UID]. * @param mbid The analogous MusicBrainz ID for this item that was extracted from a - * file. + * file. * @return A new MusicBrainz-style [UID]. */ fun musicBrainz(mode: MusicMode, mbid: UUID): UID = UID(Format.MUSICBRAINZ, mode, mbid) /** * Convert a [UID]'s string representation back into a concrete [UID] instance. + * * @param uid The [UID]'s string representation, formatted as - * `format_namespace:music_mode_int-uuid`. + * `format_namespace:music_mode_int-uuid`. * @return A [UID] converted from the string representation, or null if the string - * representation was invalid. + * representation was invalid. */ fun fromString(uid: String): UID? { val split = uid.split(':', limit = 2) @@ -224,6 +230,7 @@ sealed interface Music : Item { /** * An abstract grouping of [Song]s and other [Music] data. + * * @author Alexander Capehart (OxygenCobalt) */ sealed interface MusicParent : Music { @@ -233,6 +240,7 @@ sealed interface MusicParent : Music { /** * A song. + * * @author Alexander Capehart (OxygenCobalt) */ interface Song : Music { @@ -281,6 +289,7 @@ interface Song : Music { /** * An abstract release group. While it may be called an album, it encompasses other types of * releases like singles, EPs, and compilations. + * * @author Alexander Capehart (OxygenCobalt) */ interface Album : MusicParent { @@ -311,6 +320,7 @@ interface Album : MusicParent { /** * An abstract artist. These are actually a combination of the artist and album artist tags from * within the library, derived from [Song]s and [Album]s respectively. + * * @author Alexander Capehart (OxygenCobalt) */ interface Artist : MusicParent { @@ -336,6 +346,7 @@ interface Artist : MusicParent { /** * A genre. + * * @author Alexander Capehart (OxygenCobalt) */ interface Genre : MusicParent { @@ -350,6 +361,7 @@ interface Genre : MusicParent { /** * Run [Music.resolveName] on each instance in the given list and concatenate them into a [String] * in a localized manner. + * * @param context [Context] required * @return A concatenated string. */ @@ -359,6 +371,7 @@ fun List.resolveNames(context: Context) = /** * Returns if [Music.rawName] matches for each item in a list. Useful for scenarios where the * display information of an item must be compared without a context. + * * @param other The list of items to compare to. * @return True if they are the same (by [Music.rawName]), false otherwise. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt index 42a86f25a..fafe3cde5 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt @@ -21,6 +21,7 @@ import org.oxycblt.auxio.IntegerTable /** * Represents a data configuration corresponding to a specific type of [Music], + * * @author Alexander Capehart (OxygenCobalt) */ enum class MusicMode { @@ -35,6 +36,7 @@ enum class MusicMode { /** * The integer representation of this instance. + * * @see fromIntCode */ val intCode: Int @@ -49,6 +51,7 @@ enum class MusicMode { companion object { /** * Convert a [MusicMode] integer representation into an instance. + * * @param intCode An integer representation of a [MusicMode] * @return The corresponding [MusicMode], or null if the [MusicMode] is invalid. * @see MusicMode.intCode diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index 9b4f73884..59608d7f8 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -40,6 +40,7 @@ interface MusicRepository { /** * Add a [Listener] to this instance. This can be used to receive changes in the music library. * Will invoke all [Listener] methods to initialize the instance with the current state. + * * @param listener The [Listener] to add. * @see Listener */ @@ -47,8 +48,9 @@ interface MusicRepository { /** * Remove a [Listener] from this instance, preventing it from receiving any further updates. + * * @param listener The [Listener] to remove. Does nothing if the [Listener] was never added in - * the first place. + * the first place. * @see Listener */ fun removeListener(listener: Listener) @@ -57,6 +59,7 @@ interface MusicRepository { interface Listener { /** * Called when the current [Library] has changed. + * * @param library The new [Library], or null if no [Library] has been loaded yet. */ fun onLibraryChanged(library: Library?) diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt index 252693747..d3cf0a4fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.getSystemServiceCompat /** * User configuration specific to music system. + * * @author Alexander Capehart (OxygenCobalt) */ interface MusicSettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt index a8cae7af8..c405f5775 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt @@ -26,6 +26,7 @@ import org.oxycblt.auxio.music.system.Indexer /** * A [ViewModel] providing data specific to the music loading process. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -76,6 +77,7 @@ class MusicViewModel @Inject constructor(private val indexer: Indexer) : /** * Non-manipulated statistics bound the last successful music load. + * * @param songs The amount of [Song]s that were loaded. * @param albums The amount of [Album]s that were created. * @param artists The amount of [Artist]s that were created. diff --git a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/cache/CacheRepository.kt index 34b19a617..c68b23080 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/cache/CacheRepository.kt @@ -23,17 +23,20 @@ import org.oxycblt.auxio.util.* /** * A repository allowing access to cached metadata obtained in prior music loading operations. + * * @author Alexander Capehart (OxygenCobalt) */ interface CacheRepository { /** * Read the current [Cache], if it exists. + * * @return The stored [Cache], or null if it could not be obtained. */ suspend fun readCache(): Cache? /** * Write the list of newly-loaded [RawSong]s to the cache, replacing the prior data. + * * @param rawSongs The [rawSongs] to write to the cache. */ suspend fun writeCache(rawSongs: List) @@ -67,6 +70,7 @@ class CacheRepositoryImpl @Inject constructor(private val cachedSongsDao: Cached /** * A cache of music metadata obtained in prior music loading operations. Obtain an instance with * [CacheRepository]. + * * @author Alexander Capehart (OxygenCobalt) */ interface Cache { @@ -75,6 +79,7 @@ interface Cache { /** * Populate a [RawSong] from a cache entry, if it exists. + * * @param rawSong The [RawSong] to populate. * @return true if a cache entry could be applied to [rawSong], false otherwise. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/AudioInfo.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/AudioInfo.kt index 9411c5cfe..0b4e92912 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/AudioInfo.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/AudioInfo.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.logW /** * The properties of a [Song]'s file. + * * @param bitrateKbps The bit rate, in kilobytes-per-second. Null if it could not be parsed. * @param sampleRateHz The sample rate, in hertz. * @param resolvedMimeType The known mime type of the [Song] after it's file format was determined. @@ -44,6 +45,7 @@ data class AudioInfo( interface Provider { /** * Extract the [AudioInfo] of a given [Song]. + * * @param song The [Song] to read. * @return The [AudioInfo] of the [Song], if possible to obtain. */ @@ -53,6 +55,7 @@ data class AudioInfo( /** * A framework-backed implementation of [AudioInfo.Provider]. + * * @param context [Context] required to read audio files. */ class AudioInfoProviderImpl @Inject constructor(@ApplicationContext private val context: Context) : diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/Date.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/Date.kt index bd4764390..56ba1ab93 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/Date.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/Date.kt @@ -44,10 +44,11 @@ class Date private constructor(private val tokens: List) : Comparable /** * Resolve this instance into a human-readable date. + * * @param context [Context] required to get human-readable names. * @return If the [Date] has a valid month and year value, a more fine-grained date (ex. "Jan - * 2020") will be returned. Otherwise, a plain year value (ex. "2020") is returned. Dates will - * be properly localized. + * 2020") will be returned. Otherwise, a plain year value (ex. "2020") is returned. Dates will + * be properly localized. */ fun resolveDate(context: Context): String { if (month != null) { @@ -115,6 +116,7 @@ class Date private constructor(private val tokens: List) : Comparable * A range of [Date]s. This is used in contexts where the [Date] of an item is derived from * several sub-items and thus can have a "range" of release dates. Use [from] to create an * instance. + * * @author Alexander Capehart */ class Range @@ -127,10 +129,11 @@ class Date private constructor(private val tokens: List) : Comparable /** * Resolve this instance into a human-readable date range. + * * @param context [Context] required to get human-readable names. * @return If the date has a maximum value, then a `min - max` formatted string will be - * returned with the formatted [Date]s of the minimum and maximum dates respectively. - * Otherwise, the formatted name of the minimum [Date] will be returned. + * returned with the formatted [Date]s of the minimum and maximum dates respectively. + * Otherwise, the formatted name of the minimum [Date] will be returned. */ fun resolveDate(context: Context) = if (min != max) { @@ -149,9 +152,10 @@ class Date private constructor(private val tokens: List) : Comparable companion object { /** * Create a [Range] from the given list of [Date]s. + * * @param dates The [Date]s to use. * @return A [Range] based on the minimum and maximum [Date]s. If there are no [Date]s, - * null is returned. + * null is returned. */ fun from(dates: List): Range? { if (dates.isEmpty()) { @@ -186,6 +190,7 @@ class Date private constructor(private val tokens: List) : Comparable /** * Create a [Date] from a year component. + * * @param year The year component. * @return A new [Date] of the given component, or null if the component is invalid. */ @@ -204,38 +209,41 @@ class Date private constructor(private val tokens: List) : Comparable /** * Create a [Date] from a date component. + * * @param year The year component. * @param month The month component. * @param day The day component. * @return A new [Date] consisting of the given components. May have reduced precision if - * the components were partially invalid, and will be null if all components are invalid. + * the components were partially invalid, and will be null if all components are invalid. */ fun from(year: Int, month: Int, day: Int) = fromTokens(listOf(year, month, day)) /** * Create [Date] from a datetime component. + * * @param year The year component. * @param month The month component. * @param day The day component. * @param hour The hour component * @return A new [Date] consisting of the given components. May have reduced precision if - * the components were partially invalid, and will be null if all components are invalid. + * the components were partially invalid, and will be null if all components are invalid. */ fun from(year: Int, month: Int, day: Int, hour: Int, minute: Int) = fromTokens(listOf(year, month, day, hour, minute)) /** * Create a [Date] from a [String] timestamp. + * * @param timestamp The ISO-8601 timestamp to parse. Can have reduced precision. * @return A new [Date] consisting of the given components. May have reduced precision if - * the components were partially invalid, and will be null if all components are invalid or - * if the timestamp is invalid. + * the components were partially invalid, and will be null if all components are invalid + * or if the timestamp is invalid. */ fun from(timestamp: String): Date? { val tokens = - // Match the input with the timestamp regex. If there is no match, see if we can - // fall back to some kind of year value. - (ISO8601_REGEX.matchEntire(timestamp) + // Match the input with the timestamp regex. If there is no match, see if we can + // fall back to some kind of year value. + (ISO8601_REGEX.matchEntire(timestamp) ?: return timestamp.toIntOrNull()?.let(Companion::from)) .groupValues // Filter to the specific tokens we want and convert them to integer tokens. @@ -245,9 +253,10 @@ class Date private constructor(private val tokens: List) : Comparable /** * Create a [Date] from the given non-validated tokens. + * * @param tokens The tokens to use for each date component, in order of precision. * @return A new [Date] consisting of the given components. May have reduced precision if - * the components were partially invalid, and will be null if all components are invalid. + * the components were partially invalid, and will be null if all components are invalid. */ private fun fromTokens(tokens: List): Date? { val validated = mutableListOf() @@ -262,6 +271,7 @@ class Date private constructor(private val tokens: List) : Comparable /** * Validate a list of tokens provided by [src], and add the valid ones to [dst]. Will stop * as soon as an invalid token is found. + * * @param src The input tokens to validate. * @param dst The destination list to add valid tokens to. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/Disc.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/Disc.kt index b38db06fb..f2f479d55 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/Disc.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/Disc.kt @@ -21,6 +21,7 @@ import org.oxycblt.auxio.list.Item /** * A disc identifier for a song. + * * @param number The disc number. * @param name The name of the disc group, if any. Null if not present. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/ReleaseType.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/ReleaseType.kt index 2479444a9..2e0d972d1 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/ReleaseType.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/ReleaseType.kt @@ -24,6 +24,7 @@ import org.oxycblt.auxio.R * * This class is derived from the MusicBrainz Release Group Type specification. It can be found at: * https://musicbrainz.org/doc/Release_Group/Type + * * @author Alexander Capehart (OxygenCobalt) */ sealed class ReleaseType { @@ -38,8 +39,9 @@ sealed class ReleaseType { /** * A plain album. + * * @param refinement A specification of what kind of performance this release is. If null, the - * release is considered "Plain". + * release is considered "Plain". */ data class Album(override val refinement: Refinement?) : ReleaseType() { override val stringRes: Int @@ -54,8 +56,9 @@ sealed class ReleaseType { /** * A "Extended Play", or EP. Usually a smaller release consisting of 4-5 songs. + * * @param refinement A specification of what kind of performance this release is. If null, the - * release is considered "Plain". + * release is considered "Plain". */ data class EP(override val refinement: Refinement?) : ReleaseType() { override val stringRes: Int @@ -70,8 +73,9 @@ sealed class ReleaseType { /** * A single. Usually a release consisting of 1-2 songs. + * * @param refinement A specification of what kind of performance this release is. If null, the - * release is considered "Plain". + * release is considered "Plain". */ data class Single(override val refinement: Refinement?) : ReleaseType() { override val stringRes: Int @@ -86,8 +90,9 @@ sealed class ReleaseType { /** * A compilation. Usually consists of many songs from a variety of artists. + * * @param refinement A specification of what kind of performance this release is. If null, the - * release is considered "Plain". + * release is considered "Plain". */ data class Compilation(override val refinement: Refinement?) : ReleaseType() { override val stringRes: Int @@ -149,9 +154,10 @@ sealed class ReleaseType { /** * Parse a [ReleaseType] from a string formatted with the MusicBrainz Release Group Type * specification. + * * @param types A list of values consisting of valid release type values. * @return A [ReleaseType] consisting of the given types, or null if the types were not - * valid. + * valid. */ fun parse(types: List): ReleaseType? { val primary = types.getOrNull(0) ?: return null @@ -170,10 +176,11 @@ sealed class ReleaseType { /** * Parse "secondary" types (i.e not [Album], [EP], or [Single]) from a string formatted with * the MusicBrainz Release Group Type specification. + * * @param index The index of the release type to parse. * @param convertRefinement Code to convert a [Refinement] into a [ReleaseType] - * corresponding to the callee's context. This is used in order to handle secondary times - * that are actually [Refinement]s. + * corresponding to the callee's context. This is used in order to handle secondary times + * that are actually [Refinement]s. * @return A [ReleaseType] corresponding to the secondary type found at that index. */ private inline fun List.parseSecondaryTypes( @@ -194,10 +201,11 @@ sealed class ReleaseType { /** * Parse "secondary" types (i.e not [Album], [EP], [Single]) that do not correspond to any * child values. + * * @param type The release type value to parse. * @param convertRefinement Code to convert a [Refinement] into a [ReleaseType] - * corresponding to the callee's context. This is used in order to handle secondary times - * that are actually [Refinement]s. + * corresponding to the callee's context. This is used in order to handle secondary times + * that are actually [Refinement]s. */ private inline fun parseSecondaryTypeImpl( type: String?, diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/Separators.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/Separators.kt index dbc63447c..b069fdf5f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/Separators.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/Separators.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.music.metadata /** * Defines the allowed separator characters that can be used to delimit multi-value tags. + * * @author Alexander Capehart (OxygenCobalt) */ object Separators { diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/SeparatorsDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/SeparatorsDialog.kt index 05ac292e2..a6f88af8a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/SeparatorsDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/SeparatorsDialog.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.ui.ViewBindingDialogFragment /** * A [ViewBindingDialogFragment] that allows the user to configure the separator characters used to * split tags with multiple values. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt index 581ff63c7..7859bdccc 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt @@ -43,6 +43,7 @@ interface TagExtractor { /** * Extract the metadata of songs from [incompleteSongs] and send them to [completeSongs]. Will * terminate as soon as [incompleteSongs] is closed. + * * @param incompleteSongs A [Channel] of incomplete songs to process. * @param completeSongs A [Channel] to send completed songs to. */ @@ -105,6 +106,7 @@ class TagExtractorImpl @Inject constructor(@ApplicationContext private val conte /** * Wraps a [TagExtractor] future and processes it into a [RawSong] when completed. + * * @param context [Context] required to open the audio file. * @param rawSong [RawSong] to process. * @author Alexander Capehart (OxygenCobalt) @@ -121,6 +123,7 @@ private class Task(context: Context, private val rawSong: RawSong) { /** * Try to get a completed song from this [Task], if it has finished processing. + * * @return A [RawSong] instance if processing has completed, null otherwise. */ fun get(): RawSong? { @@ -156,8 +159,9 @@ private class Task(context: Context, private val rawSong: RawSong) { /** * Complete this instance's [RawSong] with ID3v2 Text Identification Frames. + * * @param textFrames A mapping between ID3v2 Text Identification Frame IDs and one or more - * values. + * values. */ private fun populateWithId3v2(textFrames: Map>) { // Song @@ -220,11 +224,12 @@ private class Task(context: Context, private val rawSong: RawSong) { /** * Parses the ID3v2.3 timestamp specification into a [Date] from the given Text Identification * Frames. + * * @param textFrames A mapping between ID3v2 Text Identification Frame IDs and one or more - * values. + * values. * @return A [Date] of a year value from TORY/TYER, a month and day value from TDAT, and a - * hour/minute value from TIME. No second value is included. The latter two fields may not be - * included in they cannot be parsed. Will be null if a year value could not be parsed. + * hour/minute value from TIME. No second value is included. The latter two fields may not be + * included in they cannot be parsed. Will be null if a year value could not be parsed. */ private fun parseId3v23Date(textFrames: Map>): Date? { // Assume that TDAT/TIME can refer to TYER or TORY depending on if TORY @@ -261,6 +266,7 @@ private class Task(context: Context, private val rawSong: RawSong) { /** * Complete this instance's [RawSong] with Vorbis comments. + * * @param comments A mapping between vorbis comment names and one or more vorbis comment values. */ private fun populateWithVorbis(comments: Map>) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt index 91d59e139..f4a3ca033 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt @@ -26,6 +26,7 @@ import org.oxycblt.auxio.util.nonZeroOrNull * Parse a multi-value tag based on the user configuration. If the value is already composed of more * than one value, nothing is done. Otherwise, this function will attempt to split it based on the * user's separator preferences. + * * @param settings [MusicSettings] required to obtain user separator configuration. * @return A new list of one or more [String]s. */ @@ -40,6 +41,7 @@ fun List.parseMultiValue(settings: MusicSettings) = /** * Split a [String] by the given selector, automatically handling escaped characters that satisfy * the selector. + * * @param selector A block that determines if the string should be split at a given character. * @return One or more [String]s split by the selector. */ @@ -83,19 +85,22 @@ inline fun String.splitEscaped(selector: (Char) -> Boolean): List { /** * Fix trailing whitespace or blank contents in a [String]. + * * @return A string with trailing whitespace remove,d or null if the [String] was all whitespace or - * empty. + * empty. */ fun String.correctWhitespace() = trim().ifBlank { null } /** * Fix trailing whitespace or blank contents within a list of [String]s. + * * @return A list of non-blank strings with trailing whitespace removed. */ fun List.correctWhitespace() = mapNotNull { it.correctWhitespace() } /** * Attempt to parse a string by the user's separator preferences. + * * @param settings [MusicSettings] required to obtain user separator configuration. * @return A list of one or more [String]s that were split up by the user-defined separators. */ @@ -109,9 +114,11 @@ private fun String.maybeParseBySeparators(settings: MusicSettings): List /** * Parse an ID3v2-style position + total [String] field. These fields consist of a number and an * (optional) total value delimited by a /. + * * @return The position value extracted from the string field, or null if: * - The position could not be parsed * - The position was zeroed AND the total value was not present/zeroed + * * @see transformPositionField */ fun String.parseId3v2PositionField() = @@ -122,11 +129,13 @@ fun String.parseId3v2PositionField() = /** * Parse a vorbis-style position + total field. These fields consist of two fields for the position * and total numbers. + * * @param pos The position value, or null if not present. * @param total The total value, if not present. * @return The position value extracted from the field, or null if: * - The position could not be parsed * - The position was zeroed AND the total value was not present/zeroed + * * @see transformPositionField */ fun parseVorbisPositionField(pos: String?, total: String?) = @@ -134,6 +143,7 @@ fun parseVorbisPositionField(pos: String?, total: String?) = /** * Transform a raw position + total field into a position a way that tolerates placeholder values. + * * @param pos The position value, or null if not present. * @param total The total value, if not present. * @return The position value extracted from the field, or null if: @@ -151,6 +161,7 @@ fun transformPositionField(pos: Int?, total: Int?) = * Parse a multi-value genre name using ID3 rules. This will convert any ID3v1 integer * representations of genre fields into their named counterparts, and split up singular ID3v2-style * integer genre fields into one or more genres. + * * @param settings [MusicSettings] required to obtain user separator configuration. * @return A list of one or more genre names.. */ @@ -164,6 +175,7 @@ fun List.parseId3GenreNames(settings: MusicSettings) = /** * Parse a single ID3v1/ID3v2 integer genre field into their named representations. + * * @param settings [MusicSettings] required to obtain user separator configuration. * @return A list of one or more genre names. */ @@ -172,8 +184,9 @@ private fun String.parseId3MultiValueGenre(settings: MusicSettings) = /** * Parse an ID3v1 integer genre field. + * * @return A named genre if the field is a valid integer, "Cover" or "Remix" if the field is - * "CR"/"RX" respectively, and nothing if the field is not a valid ID3v1 integer genre. + * "CR"/"RX" respectively, and nothing if the field is not a valid ID3v1 integer genre. */ private fun String.parseId3v1Genre(): String? { // ID3v1 genres are a plain integer value without formatting, so in that case @@ -200,6 +213,7 @@ private val ID3V2_GENRE_RE = Regex("((?:\\((\\d+|RX|CR)\\))*)(.+)?") /** * Parse an ID3v2 integer genre field, which has support for multiple genre values and combined * named/integer genres. + * * @return A list of one or more genres, or null if the field is not a valid ID3v2 integer genre. */ private fun String.parseId3v2Genre(): List? { diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt index de3c28c75..3803e12b4 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.metadata.vorbis.VorbisComment /** * Processing wrapper for [Metadata] that allows organized access to text-based audio tags. + * * @param metadata The [Metadata] to wrap. * @author Alexander Capehart (OxygenCobalt) */ @@ -79,8 +80,9 @@ class TextTags(metadata: Metadata) { /** * Copies and sanitizes a possibly invalid string outputted from ExoPlayer. + * * @return A new string allocated in a memory-safe manner with any UTF-8 errors replaced with - * the Unicode replacement byte sequence. + * the Unicode replacement byte sequence. */ private fun String.sanitize() = String(encodeToByteArray()) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/model/Library.kt b/app/src/main/java/org/oxycblt/auxio/music/model/Library.kt index 54c99a084..535420dc4 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/model/Library.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/model/Library.kt @@ -47,14 +47,16 @@ interface Library { /** * Finds a [Music] item [T] in the library by it's [Music.UID]. + * * @param uid The [Music.UID] to search for. * @return The [T] corresponding to the given [Music.UID], or null if nothing could be found or - * the [Music.UID] did not correspond to a [T]. + * the [Music.UID] did not correspond to a [T]. */ fun find(uid: Music.UID): T? /** * Convert a [Song] from an another library into a [Song] in this [Library]. + * * @param song The [Song] to convert. * @return The analogous [Song] in this [Library], or null if it does not exist. */ @@ -62,6 +64,7 @@ interface Library { /** * Convert a [MusicParent] from an another library into a [MusicParent] in this [Library]. + * * @param parent The [MusicParent] to convert. * @return The analogous [Album] in this [Library], or null if it does not exist. */ @@ -69,6 +72,7 @@ interface Library { /** * Find a [Song] instance corresponding to the given Intent.ACTION_VIEW [Uri]. + * * @param context [Context] required to analyze the [Uri]. * @param uri [Uri] to search for. * @return A [Song] corresponding to the given [Uri], or null if one could not be found. @@ -78,6 +82,7 @@ interface Library { companion object { /** * Create an instance of [Library]. + * * @param rawSongs [RawSong]s to create the library out of. * @param settings [MusicSettings] required. */ @@ -117,9 +122,10 @@ private class LibraryImpl(rawSongs: List, settings: MusicSettings) : Li /** * Finds a [Music] item [T] in the library by it's [Music.UID]. + * * @param uid The [Music.UID] to search for. * @return The [T] corresponding to the given [Music.UID], or null if nothing could be found or - * the [Music.UID] did not correspond to a [T]. + * the [Music.UID] did not correspond to a [T]. */ @Suppress("UNCHECKED_CAST") override fun find(uid: Music.UID) = uidMap[uid] as? T @@ -130,21 +136,22 @@ private class LibraryImpl(rawSongs: List, settings: MusicSettings) : Li override fun findSongForUri(context: Context, uri: Uri) = context.contentResolverSafe.useQuery( uri, arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE)) { cursor -> - cursor.moveToFirst() - // We are weirdly limited to DISPLAY_NAME and SIZE when trying to locate a - // song. Do what we can to hopefully find the song the user wanted to open. - val displayName = - cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) - val size = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)) - songs.find { it.path.name == displayName && it.size == size } - } + cursor.moveToFirst() + // We are weirdly limited to DISPLAY_NAME and SIZE when trying to locate a + // song. Do what we can to hopefully find the song the user wanted to open. + val displayName = + cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) + val size = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)) + songs.find { it.path.name == displayName && it.size == size } + } /** * Build a list [SongImpl]s from the given [RawSong]. + * * @param rawSongs The [RawSong]s to build the [SongImpl]s from. * @param settings [MusicSettings] to obtain user parsing configuration. * @return A sorted list of [SongImpl]s derived from the [RawSong] that should be suitable for - * grouping. + * grouping. */ private fun buildSongs(rawSongs: List, settings: MusicSettings) = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) @@ -152,11 +159,12 @@ private class LibraryImpl(rawSongs: List, settings: MusicSettings) : Li /** * Build a list of [Album]s from the given [Song]s. + * * @param songs The [Song]s to build [Album]s from. These will be linked with their respective - * [Album]s when created. + * [Album]s when created. * @param settings [MusicSettings] to obtain user parsing configuration. * @return A non-empty list of [Album]s. These [Album]s will be incomplete and must be linked - * with parent [Artist] instances in order to be usable. + * with parent [Artist] instances in order to be usable. */ private fun buildAlbums(songs: List, settings: MusicSettings): List { // Group songs by their singular raw album, then map the raw instances and their @@ -171,15 +179,16 @@ private class LibraryImpl(rawSongs: List, settings: MusicSettings) : Li * Group up [Song]s and [Album]s into [Artist] instances. Both of these items are required as * they group into [Artist] instances much differently, with [Song]s being grouped primarily by * artist names, and [Album]s being grouped primarily by album artist names. + * * @param songs The [Song]s to build [Artist]s from. One [Song] can result in the creation of - * one or more [Artist] instances. These will be linked with their respective [Artist]s when - * created. + * one or more [Artist] instances. These will be linked with their respective [Artist]s when + * created. * @param albums The [Album]s to build [Artist]s from. One [Album] can result in the creation of - * one or more [Artist] instances. These will be linked with their respective [Artist]s when - * created. + * one or more [Artist] instances. These will be linked with their respective [Artist]s when + * created. * @param settings [MusicSettings] to obtain user parsing configuration. * @return A non-empty list of [Artist]s. These [Artist]s will consist of the combined groupings - * of [Song]s and [Album]s. + * of [Song]s and [Album]s. */ private fun buildArtists( songs: List, @@ -210,9 +219,10 @@ private class LibraryImpl(rawSongs: List, settings: MusicSettings) : Li /** * Group up [Song]s into [Genre] instances. + * * @param [songs] The [Song]s to build [Genre]s from. One [Song] can result in the creation of - * one or more [Genre] instances. These will be linked with their respective [Genre]s when - * created. + * one or more [Genre] instances. These will be linked with their respective [Genre]s when + * created. * @param settings [MusicSettings] to obtain user parsing configuration. * @return A non-empty list of [Genre]s. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt b/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt index 1bf87f5bf..91edf4378 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt @@ -46,14 +46,15 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * Library-backed implementation of [Song]. + * * @param rawSong The [RawSong] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. * @author Alexander Capehart (OxygenCobalt) */ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { override val uid = - // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. - rawSong.musicBrainzId?.toUuidOrNull()?.let { Music.UID.musicBrainz(MusicMode.SONGS, it) } + // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. + rawSong.musicBrainzId?.toUuidOrNull()?.let { Music.UID.musicBrainz(MusicMode.SONGS, it) } ?: Music.UID.auxio(MusicMode.SONGS) { // Song UIDs are based on the raw data without parsing so that they remain // consistent across music setting changes. Parents are not held up to the @@ -164,6 +165,7 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { /** * Links this [Song] with a parent [Album]. + * * @param album The parent [Album] to link to. */ fun link(album: AlbumImpl) { @@ -172,6 +174,7 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { /** * Links this [Song] with a parent [Artist]. + * * @param artist The parent [Artist] to link to. */ fun link(artist: ArtistImpl) { @@ -180,6 +183,7 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { /** * Links this [Song] with a parent [Genre]. + * * @param genre The parent [Genre] to link to. */ fun link(genre: GenreImpl) { @@ -188,6 +192,7 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { /** * Perform final validation and organization on this instance. + * * @return This instance upcasted to [Song]. */ fun finalize(): Song { @@ -218,10 +223,11 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { /** * Library-backed implementation of [Album]. + * * @param rawAlbum The [RawAlbum] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. * @param songs The [Song]s that are a part of this [Album]. These items will be linked to this - * [Album]. + * [Album]. * @author Alexander Capehart (OxygenCobalt) */ class AlbumImpl( @@ -230,8 +236,8 @@ class AlbumImpl( override val songs: List ) : Album { override val uid = - // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. - rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) } + // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. + rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) } ?: Music.UID.auxio(MusicMode.ALBUMS) { // Hash based on only names despite the presence of a date to increase stability. // I don't know if there is any situation where an artist will have two albums with @@ -286,6 +292,7 @@ class AlbumImpl( /** * Links this [Album] with a parent [Artist]. + * * @param artist The parent [Artist] to link to. */ fun link(artist: ArtistImpl) { @@ -294,6 +301,7 @@ class AlbumImpl( /** * Perform final validation and organization on this instance. + * * @return This instance upcasted to [Album]. */ fun finalize(): Album { @@ -313,11 +321,12 @@ class AlbumImpl( /** * Library-backed implementation of [Artist]. + * * @param rawArtist The [RawArtist] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. * @param songAlbums A list of the [Song]s and [Album]s that are a part of this [Artist] , either - * through artist or album artist tags. Providing [Song]s to the artist is optional. These instances - * will be linked to this [Artist]. + * through artist or album artist tags. Providing [Song]s to the artist is optional. These + * instances will be linked to this [Artist]. * @author Alexander Capehart (OxygenCobalt) */ class ArtistImpl( @@ -326,8 +335,8 @@ class ArtistImpl( songAlbums: List ) : Artist { override val uid = - // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. - rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) } + // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. + rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) } ?: Music.UID.auxio(MusicMode.ARTISTS) { update(rawArtist.name) } override val rawName = rawArtist.name override val rawSortName = rawArtist.sortName @@ -379,14 +388,16 @@ class ArtistImpl( * Returns the original position of this [Artist]'s [RawArtist] within the given [RawArtist] * list. This can be used to create a consistent ordering within child [Artist] lists based on * the original tag order. + * * @param rawArtists The [RawArtist] instances to check. It is assumed that this [Artist]'s - * [RawArtist] will be within the list. + * [RawArtist] will be within the list. * @return The index of the [Artist]'s [RawArtist] within the list. */ fun getOriginalPositionIn(rawArtists: List) = rawArtists.indexOf(rawArtist) /** * Perform final validation and organization on this instance. + * * @return This instance upcasted to [Artist]. */ fun finalize(): Artist { @@ -400,6 +411,7 @@ class ArtistImpl( } /** * Library-backed implementation of [Genre]. + * * @param rawGenre [RawGenre] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. * @param songs Child [SongImpl]s of this instance. @@ -450,14 +462,16 @@ class GenreImpl( * Returns the original position of this [Genre]'s [RawGenre] within the given [RawGenre] list. * This can be used to create a consistent ordering within child [Genre] lists based on the * original tag order. + * * @param rawGenres The [RawGenre] instances to check. It is assumed that this [Genre] 's - * [RawGenre] will be within the list. + * [RawGenre] will be within the list. * @return The index of the [Genre]'s [RawGenre] within the list. */ fun getOriginalPositionIn(rawGenres: List) = rawGenres.indexOf(rawGenre) /** * Perform final validation and organization on this instance. + * * @return This instance upcasted to [Genre]. */ fun finalize(): Music { @@ -468,6 +482,7 @@ class GenreImpl( /** * Update a [MessageDigest] with a lowercase [String]. + * * @param string The [String] to hash. If null, it will not be hashed. */ @VisibleForTesting @@ -481,6 +496,7 @@ fun MessageDigest.update(string: String?) { /** * Update a [MessageDigest] with the string representation of a [Date]. + * * @param date The [Date] to hash. If null, nothing will be done. */ @VisibleForTesting @@ -494,6 +510,7 @@ fun MessageDigest.update(date: Date?) { /** * Update a [MessageDigest] with the lowercase versions of all of the input [String]s. + * * @param strings The [String]s to hash. If a [String] is null, it will not be hashed. */ @VisibleForTesting @@ -503,6 +520,7 @@ fun MessageDigest.update(strings: List) { /** * Update a [MessageDigest] with the little-endian bytes of a [Int]. + * * @param n The [Int] to write. If null, nothing will be done. */ @VisibleForTesting @@ -520,6 +538,7 @@ private val COLLATOR: Collator = Collator.getInstance().apply { strength = Colla /** * Provided implementation to create a [CollationKey] in the way described by [Music.collationKey]. * This should be used in all overrides of all [CollationKey]. + * * @param musicSettings [MusicSettings] required for user parsing configuration. * @return A [CollationKey] that follows the specification described by [Music.collationKey]. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/model/RawMusic.kt b/app/src/main/java/org/oxycblt/auxio/music/model/RawMusic.kt index f532266c7..b83ec643a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/model/RawMusic.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/model/RawMusic.kt @@ -24,6 +24,7 @@ import org.oxycblt.auxio.music.storage.Directory /** * Raw information about a [SongImpl] obtained from the filesystem/Extractor instances. + * * @author Alexander Capehart (OxygenCobalt) */ class RawSong( @@ -88,6 +89,7 @@ class RawSong( /** * Raw information about an [AlbumImpl] obtained from the component [SongImpl] instances. + * * @author Alexander Capehart (OxygenCobalt) */ class RawAlbum( @@ -134,6 +136,7 @@ class RawAlbum( /** * Raw information about an [ArtistImpl] obtained from the component [SongImpl] and [AlbumImpl] * instances. + * * @author Alexander Capehart (OxygenCobalt) */ class RawArtist( @@ -175,6 +178,7 @@ class RawArtist( /** * Raw information about a [GenreImpl] obtained from the component [SongImpl] instances. + * * @author Alexander Capehart (OxygenCobalt) */ class RawGenre( diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/DirectoryAdapter.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/DirectoryAdapter.kt index dcdedc0ef..b7329d4be 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/DirectoryAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/DirectoryAdapter.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.util.inflater /** * [RecyclerView.Adapter] that manages a list of [Directory] instances. + * * @param listener A [DirectoryAdapter.Listener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -48,6 +49,7 @@ class DirectoryAdapter(private val listener: Listener) : /** * Add a [Directory] to the end of the list. + * * @param dir The [Directory] to add. */ fun add(dir: Directory) { @@ -61,6 +63,7 @@ class DirectoryAdapter(private val listener: Listener) : /** * Add a list of [Directory] instances to the end of the list. + * * @param dirs The [Directory instances to add. */ fun addAll(dirs: List) { @@ -71,6 +74,7 @@ class DirectoryAdapter(private val listener: Listener) : /** * Remove a [Directory] from the list. + * * @param dir The [Directory] to remove. Must exist in the list. */ fun remove(dir: Directory) { @@ -87,12 +91,14 @@ class DirectoryAdapter(private val listener: Listener) : /** * A [RecyclerView.Recycler] that displays a [Directory]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class MusicDirViewHolder private constructor(private val binding: ItemMusicDirBinding) : DialogRecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param dir The new [Directory] to bind. * @param listener A [DirectoryAdapter.Listener] to bind interactions to. */ @@ -104,6 +110,7 @@ class MusicDirViewHolder private constructor(private val binding: ItemMusicDirBi companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt index ca0cdee6c..a65c1cf17 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.R /** * A full absolute path to a file. Only intended for display purposes. For accessing files, URIs are * preferred in all cases due to scoped storage limitations. + * * @param name The name of the file. * @param parent The parent [Directory] of the file. * @author Alexander Capehart (OxygenCobalt) @@ -36,6 +37,7 @@ data class Path(val name: String, val parent: Directory) /** * A volume-aware relative path to a directory. + * * @param volume The [StorageVolume] that the [Directory] is contained in. * @param relativePath The relative path from within the [StorageVolume] to the [Directory]. * @author Alexander Capehart (OxygenCobalt) @@ -43,6 +45,7 @@ data class Path(val name: String, val parent: Directory) class Directory private constructor(val volume: StorageVolume, val relativePath: String) { /** * Resolve the [Directory] instance into a human-readable path name. + * * @param context [Context] required to obtain volume descriptions. * @return A human-readable path. * @see StorageVolume.getDescription @@ -55,8 +58,9 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: * violation of the document tree URI contract, but it's also the only one can sensibly work * with these uris in the UI, and it doesn't exactly matter since we never write or read to * directory. + * * @return A URI [String] abiding by the document tree specification, or null if the [Directory] - * is not valid. + * is not valid. */ fun toDocumentTreeUri() = // Document tree URIs consist of a prefixed volume name followed by a relative path. @@ -84,9 +88,10 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: /** * Create a new directory instance from the given components. + * * @param volume The [StorageVolume] that the [Directory] is contained in. * @param relativePath The relative path from within the [StorageVolume] to the [Directory]. - * Will be stripped of any trailing separators for a consistent internal representation. + * Will be stripped of any trailing separators for a consistent internal representation. * @return A new [Directory] created from the components. */ fun from(volume: StorageVolume, relativePath: String) = @@ -97,8 +102,9 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: * Create a new directory from a document tree URI. This is a huge violation of the document * tree URI contract, but it's also the only one can sensibly work with these uris in the * UI, and it doesn't exactly matter since we never write or read directory. + * * @param storageManager [StorageManager] in order to obtain the [StorageVolume] specified - * in the given URI. + * in the given URI. * @param uri The URI string to parse into a [Directory]. * @return A new [Directory] parsed from the URI, or null if the URI is not valid. */ @@ -123,26 +129,29 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: /** * Represents the configuration for specific directories to filter to/from when loading music. + * * @param dirs A list of [Directory] instances. How these are interpreted depends on [shouldInclude] * @param shouldInclude True if the library should only load from the [Directory] instances, false - * if the library should not load from the [Directory] instances. + * if the library should not load from the [Directory] instances. * @author Alexander Capehart (OxygenCobalt) */ data class MusicDirectories(val dirs: List, val shouldInclude: Boolean) /** * A mime type of a file. Only intended for display. + * * @param fromExtension The mime type obtained by analyzing the file extension. * @param fromFormat The mime type obtained by analyzing the file format. Null if could not be - * obtained. + * obtained. * @author Alexander Capehart (OxygenCobalt) */ data class MimeType(val fromExtension: String, val fromFormat: String?) { /** * Resolve the mime type into a human-readable format name, such as "Ogg Vorbis". + * * @param context [Context] required to obtain human-readable strings. * @return A human-readable name for this mime type. Will first try [fromFormat], then falling - * back to [fromExtension], and then null if that fails. + * back to [fromExtension], and then null if that fails. */ fun resolveName(context: Context): String? { // We try our best to produce a more readable name for the common audio formats. diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/MediaStoreExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/MediaStoreExtractor.kt index 32912061d..78174b946 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/MediaStoreExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/MediaStoreExtractor.kt @@ -42,22 +42,25 @@ import org.oxycblt.auxio.util.logD * music extraction process and primarily intended for redundancy for files not natively supported * by other extractors. Solely relying on this is not recommended, as it often produces bad * metadata. + * * @author Alexander Capehart (OxygenCobalt) */ interface MediaStoreExtractor { /** * Query the media database. + * * @return A new [Query] returned from the media database. */ suspend fun query(): Query /** * Consume the [Cursor] loaded after [query]. + * * @param query The [Query] to consume. * @param cache A [Cache] used to avoid extracting metadata for cached songs, or null if no - * [Cache] was available. + * [Cache] was available. * @param incompleteSongs A channel where songs that could not be retrieved from the [Cache] - * should be sent to. + * should be sent to. * @param completeSongs A channel where completed songs should be sent to. */ suspend fun consume( @@ -79,6 +82,7 @@ interface MediaStoreExtractor { companion object { /** * Create a framework-backed instance. + * * @param context [Context] required. * @param musicSettings [MusicSettings] required. * @return A new [MediaStoreExtractor] that will work best on the device's API level. @@ -158,27 +162,28 @@ private abstract class BaseMediaStoreExtractor( context.contentResolverSafe.useQuery( MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI, arrayOf(MediaStore.Audio.Genres._ID, MediaStore.Audio.Genres.NAME)) { genreCursor -> - val idIndex = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID) - val nameIndex = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME) + val idIndex = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID) + val nameIndex = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME) - while (genreCursor.moveToNext()) { - val id = genreCursor.getLong(idIndex) - val name = genreCursor.getStringOrNull(nameIndex) ?: continue + while (genreCursor.moveToNext()) { + val id = genreCursor.getLong(idIndex) + val name = genreCursor.getStringOrNull(nameIndex) ?: continue - context.contentResolverSafe.useQuery( - MediaStore.Audio.Genres.Members.getContentUri(VOLUME_EXTERNAL, id), - arrayOf(MediaStore.Audio.Genres.Members._ID)) { cursor -> - val songIdIndex = - cursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.Members._ID) + context.contentResolverSafe.useQuery( + MediaStore.Audio.Genres.Members.getContentUri(VOLUME_EXTERNAL, id), + arrayOf(MediaStore.Audio.Genres.Members._ID)) { cursor -> + val songIdIndex = + cursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.Members._ID) - while (cursor.moveToNext()) { - // Assume that a song can't inhabit multiple genre entries, as I doubt - // MediaStore is actually aware that songs can have multiple genres. - genreNamesMap[cursor.getLong(songIdIndex)] = name - } + while (cursor.moveToNext()) { + // Assume that a song can't inhabit multiple genre entries, as I + // doubt + // MediaStore is actually aware that songs can have multiple genres. + genreNamesMap[cursor.getLong(songIdIndex)] = name + } + } } } - } logD("Finished initialization in ${System.currentTimeMillis() - start}ms") return wrapQuery(cursor, genreNamesMap) @@ -232,15 +237,17 @@ private abstract class BaseMediaStoreExtractor( /** * The companion template to add to the projection's selector whenever arguments are added by * [addDirToSelector]. + * * @see addDirToSelector */ protected abstract val dirSelectorTemplate: String /** * Add a [Directory] to the given list of projection selector arguments. + * * @param dir The [Directory] to add. * @param args The destination list to append selector arguments to that are analogous to the - * given [Directory]. + * given [Directory]. * @return true if the [Directory] was added, false otherwise. * @see dirSelectorTemplate */ @@ -431,6 +438,7 @@ private class Api21MediaStoreExtractor(context: Context, musicSettings: MusicSet /** * A [BaseMediaStoreExtractor] that implements common behavior supported from API 29 onwards. + * * @param context [Context] required to query the media database. * @author Alexander Capehart (OxygenCobalt) */ @@ -494,8 +502,8 @@ private abstract class BaseApi29MediaStoreExtractor( /** * A [BaseMediaStoreExtractor] that completes the music loading process in a way compatible with at - * API - * 29. + * API 29. + * * @param context [Context] required to query the media database. * @author Alexander Capehart (OxygenCobalt) */ @@ -535,6 +543,7 @@ private class Api29MediaStoreExtractor(context: Context, musicSettings: MusicSet /** * A [BaseMediaStoreExtractor] that completes the music loading process in a way compatible from API * 30 onwards. + * * @param context [Context] required to query the media database. * @author Alexander Capehart (OxygenCobalt) */ @@ -584,8 +593,9 @@ private class Api30MediaStoreExtractor(context: Context, musicSettings: MusicSet * Unpack the track number from a combined track + disc [Int] field. These fields appear within * MediaStore's TRACK column, and combine the track and disc value into a single field where the * disc number is the 4th+ digit. + * * @return The track number extracted from the combined integer value, or null if the value was - * zero. + * zero. */ private fun Int.unpackTrackNo() = transformPositionField(mod(1000), null) @@ -593,6 +603,7 @@ private fun Int.unpackTrackNo() = transformPositionField(mod(1000), null) * Unpack the disc number from a combined track + disc [Int] field. These fields appear within * MediaStore's TRACK column, and combine the track and disc value into a single field where the * disc number is the 4th+ digit. + * * @return The disc number extracted from the combined integer field, or null if the value was zero. */ private fun Int.unpackDiscNo() = transformPositionField(div(1000), null) diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt index f6ea77464..23dae317e 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/MusicDirsDialog.kt @@ -41,6 +41,7 @@ import org.oxycblt.auxio.util.showToast /** * Dialog that manages the music dirs setting. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -149,8 +150,9 @@ class MusicDirsDialog : /** * Add a Document Tree [Uri] chosen by the user to the current [MusicDirectories] instance. + * * @param uri The document tree [Uri] to add, chosen by the user. Will do nothing if the [Uri] - * is null or not valid. + * is null or not valid. */ private fun addDocumentTreeUriToDirs(uri: Uri?) { if (uri == null) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt index 6de6c4b3f..55537ade9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/StorageUtil.kt @@ -42,10 +42,11 @@ val Context.contentResolverSafe: ContentResolver /** * A shortcut for querying the [ContentResolver] database. + * * @param uri The [Uri] of content to retrieve. * @param projection A list of SQL columns to query from the database. * @param selector A SQL selection statement to filter results. Spaces where arguments should be - * filled in are represented with a "?". + * filled in are represented with a "?". * @param args The arguments used for the selector. * @return A [Cursor] of the queried values, organized by the column projection. * @throws IllegalStateException If the [ContentResolver] did not return the queried [Cursor]. @@ -61,13 +62,14 @@ fun ContentResolver.safeQuery( /** * A shortcut for [safeQuery] with [use] applied, automatically cleaning up the [Cursor]'s resources * when no longer used. + * * @param uri The [Uri] of content to retrieve. * @param projection A list of SQL columns to query from the database. * @param selector A SQL selection statement to filter results. Spaces where arguments should be - * filled in are represented with a "?". + * filled in are represented with a "?". * @param args The arguments used for the selector. * @param block The block of code to run with the queried [Cursor]. Will not be ran if the [Cursor] - * is empty. + * is empty. * @throws IllegalStateException If the [ContentResolver] did not return the queried [Cursor]. * @see ContentResolver.query */ @@ -84,6 +86,7 @@ private val EXTERNAL_COVERS_URI = Uri.parse("content://media/external/audio/albu /** * Convert a [MediaStore] Song ID into a [Uri] to it's audio file. + * * @return An external storage audio file [Uri]. May not exist. * @see ContentUris.withAppendedId * @see MediaStore.Audio.Media.EXTERNAL_CONTENT_URI @@ -94,6 +97,7 @@ fun Long.toAudioUri() = /** * Convert a [MediaStore] Album ID into a [Uri] to it's system-provided album cover. This cover will * be fast to load, but will be lower quality. + * * @return An external storage image [Uri]. May not exist. * @see ContentUris.withAppendedId */ @@ -105,6 +109,7 @@ fun Long.toCoverUri() = ContentUris.withAppendedId(EXTERNAL_COVERS_URI, this) /** * Provides the analogous method to [StorageManager.getStorageVolumes] method that is usable from * API 21 to API 23, in which the [StorageManager] API was hidden and differed greatly. + * * @see StorageManager.getStorageVolumes */ @Suppress("NewApi") @@ -114,6 +119,7 @@ private val SM_API21_GET_VOLUME_LIST_METHOD: Method by /** * Provides the analogous method to [StorageVolume.getDirectory] method that is usable from API 21 * to API 23, in which the [StorageVolume] API was hidden and differed greatly. + * * @see StorageVolume.getDirectory */ @Suppress("NewApi") @@ -122,6 +128,7 @@ private val SV_API21_GET_PATH_METHOD: Method by lazyReflectedMethod(StorageVolum /** * The [StorageVolume] considered the "primary" volume by the system, obtained in a * version-compatible manner. + * * @see StorageManager.getPrimaryStorageVolume * @see StorageVolume.isPrimary */ @@ -131,6 +138,7 @@ val StorageManager.primaryStorageVolumeCompat: StorageVolume /** * The list of [StorageVolume]s currently recognized by [StorageManager], in a version-compatible * manner. + * * @see StorageManager.getStorageVolumes */ val StorageManager.storageVolumesCompat: List @@ -145,6 +153,7 @@ val StorageManager.storageVolumesCompat: List /** * The the absolute path to this [StorageVolume]'s directory within the file-system, in a * version-compatible manner. Will be null if the [StorageVolume] cannot be read. + * * @see StorageVolume.getDirectory */ val StorageVolume.directoryCompat: String? @@ -164,6 +173,7 @@ val StorageVolume.directoryCompat: String? /** * Get the human-readable description of this volume, such as "Internal Shared Storage". + * * @param context [Context] required to obtain human-readable string resources. * @return A human-readable name for this volume. */ @@ -173,6 +183,7 @@ fun StorageVolume.getDescriptionCompat(context: Context): String = getDescriptio /** * If this [StorageVolume] is considered the "Primary" volume where the Android System is kept. May * still be a removable volume. + * * @see StorageVolume.isPrimary */ val StorageVolume.isPrimaryCompat: Boolean @@ -181,6 +192,7 @@ val StorageVolume.isPrimaryCompat: Boolean /** * If this storage is "emulated", i.e intrinsic to the device, obtained in a version compatible * manner. + * * @see StorageVolume.isEmulated */ val StorageVolume.isEmulatedCompat: Boolean @@ -198,6 +210,7 @@ val StorageVolume.isInternalCompat: Boolean /** * The unique identifier for this [StorageVolume], obtained in a version compatible manner. Can be * null. + * * @see StorageVolume.getUuid */ val StorageVolume.uuidCompat: String? @@ -206,6 +219,7 @@ val StorageVolume.uuidCompat: String? /** * The current state of this [StorageVolume], such as "mounted" or "read-only", obtained in a * version compatible manner. + * * @see StorageVolume.getState */ val StorageVolume.stateCompat: String @@ -214,6 +228,7 @@ val StorageVolume.stateCompat: String /** * Returns the name of this volume that can be used to interact with [MediaStore], in a version * compatible manner. Will be null if the volume is not scanned by [MediaStore]. + * * @see StorageVolume.getMediaStoreVolumeName */ val StorageVolume.mediaStoreVolumeNameCompat: String? diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt index 5820a096d..8f1f77561 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt @@ -68,6 +68,7 @@ interface Indexer { * Register a [Controller] for this instance. This instance will handle any commands to start * the music loading process. There can be only one [Controller] at a time. Will invoke all * [Listener] methods to initialize the instance with the current state. + * * @param controller The [Controller] to register. Will do nothing if already registered. */ fun registerController(controller: Controller) @@ -75,8 +76,9 @@ interface Indexer { /** * Unregister the [Controller] from this instance, prevent it from recieving any further * commands. + * * @param controller The [Controller] to unregister. Must be the current [Controller]. Does - * nothing if invoked by another [Controller] implementation. + * nothing if invoked by another [Controller] implementation. */ fun unregisterController(controller: Controller) @@ -84,14 +86,16 @@ interface Indexer { * Register the [Listener] for this instance. This can be used to receive rapid-fire updates to * the current music loading state. There can be only one [Listener] at a time. Will invoke all * [Listener] methods to initialize the instance with the current state. + * * @param listener The [Listener] to add. */ fun registerListener(listener: Listener) /** * Unregister a [Listener] from this instance, preventing it from recieving any further updates. + * * @param listener The [Listener] to unregister. Must be the current [Listener]. Does nothing if - * invoked by another [Listener] implementation. + * invoked by another [Listener] implementation. * @see Listener */ fun unregisterListener(listener: Listener) @@ -99,9 +103,10 @@ interface Indexer { /** * Start the indexing process. This should be done from in the background from [Controller]'s * context after a command has been received to start the process. + * * @param context [Context] required to load music. * @param withCache Whether to use the cache or not when loading. If false, the cache will still - * be written, but no cache entries will be loaded into the new library. + * be written, but no cache entries will be loaded into the new library. * @param scope The [CoroutineScope] to run the indexing job in. * @return The [Job] stacking the indexing status. */ @@ -111,8 +116,9 @@ interface Indexer { * Request that the music library should be reloaded. This should be used by components that do * not manage the indexing process in order to signal that the [Indexer.Controller] should call * [index] eventually. + * * @param withCache Whether to use the cache when loading music. Does nothing if there is no - * [Indexer.Controller]. + * [Indexer.Controller]. */ fun requestReindex(withCache: Boolean) @@ -126,6 +132,7 @@ interface Indexer { sealed class State { /** * Music loading is ongoing. + * * @param indexing The current music loading progress.. * @see Indexer.Indexing */ @@ -133,6 +140,7 @@ interface Indexer { /** * Music loading has completed. + * * @param result The outcome of the music loading process. */ data class Complete(val result: Result) : State() @@ -140,6 +148,7 @@ interface Indexer { /** * Represents the current progress of the music loader. Usually encapsulated in a [State]. + * * @see State.Indexing */ sealed class Indexing { @@ -150,6 +159,7 @@ interface Indexer { /** * Music loading has a definite progress. + * * @param current The current amount of songs that have been loaded. * @param total The projected total amount of songs that will be loaded. */ @@ -182,7 +192,7 @@ interface Indexer { * Notes: * - Null means that no loading is going on, but no load has completed either. * - [State.Complete] may represent a previous load, if the current loading process was - * canceled for one reason or another. + * canceled for one reason or another. */ fun onIndexerStateChanged(state: State?) } @@ -195,8 +205,9 @@ interface Indexer { /** * Called when a new music loading process was requested. Implementations should forward * this to [index]. + * * @param withCache Whether to use the cache or not when loading. If false, the cache should - * still be written, but no cache entries will be loaded into the new library. + * still be written, but no cache entries will be loaded into the new library. * @see index */ fun onStartIndexing(withCache: Boolean) @@ -390,8 +401,9 @@ constructor( * Emit a new [Indexer.State.Indexing] state. This can be used to signal the current state of * the music loading process to external code. Assumes that the callee has already checked if * they have not been canceled and thus have the ability to emit a new state. + * * @param indexing The new [Indexer.Indexing] state to emit, or null if no loading process is - * occurring. + * occurring. */ @Synchronized private fun emitIndexing(indexing: Indexer.Indexing?) { @@ -409,8 +421,9 @@ constructor( * Emit a new [Indexer.State.Complete] state. This can be used to signal the completion of the * music loading process to external code. Will check if the callee has not been canceled and * thus has the ability to emit a new state + * * @param result The new [Result] to emit, representing the outcome of the music loading - * process. + * process. */ private suspend fun emitCompletion(result: Result) { yield() diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt index 67d301c36..ac07b8757 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.newMainPendingIntent /** * A dynamic [ForegroundServiceNotification] that shows the current music loading state. + * * @param context [Context] required to create the notification. * @author Alexander Capehart (OxygenCobalt) */ @@ -53,6 +54,7 @@ class IndexingNotification(private val context: Context) : /** * Update this notification with the new music loading state. + * * @param indexing The new music loading state to display in the notification. * @return true if the notification updated, false otherwise */ @@ -90,6 +92,7 @@ class IndexingNotification(private val context: Context) : /** * A static [ForegroundServiceNotification] that signals to the user that the app is currently * monitoring the music library for changes. + * * @author Alexander Capehart (OxygenCobalt) */ class ObservingNotification(context: Context) : diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt index 81e22ce51..abf8bb199 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt @@ -50,9 +50,9 @@ import org.oxycblt.auxio.util.logD * This [Service] also handles automatic rescanning, as that is a similarly long-running background * operation that would be unsuitable elsewhere in the app. * - * TODO: Unify with PlaybackService as part of the service independence project - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Unify with PlaybackService as part of the service independence project */ @AndroidEntryPoint class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener { @@ -176,6 +176,7 @@ class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener { /** * Update the current state to "Active", in which the service signals that music loading is * on-going. + * * @param state The current music loading state. */ private fun updateActiveSession(state: Indexer.Indexing) { diff --git a/app/src/main/java/org/oxycblt/auxio/picker/ArtistChoiceAdapter.kt b/app/src/main/java/org/oxycblt/auxio/picker/ArtistChoiceAdapter.kt index 48cc378ed..3687edeea 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/ArtistChoiceAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/ArtistChoiceAdapter.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.inflater /** * An [RecyclerView.Adapter] that displays a list of [Artist] choices. + * * @param listener A [ClickableListListener] to bind interactions to. * @author OxygenCobalt. */ @@ -46,6 +47,7 @@ class ArtistChoiceAdapter(private val listener: ClickableListListener) : /** * Immediately update the [Artist] choices. + * * @param newArtists The new [Artist]s to show. */ fun submitList(newArtists: List) { @@ -64,6 +66,7 @@ class ArtistChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : DialogRecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param artist The new [Artist] to bind. * @param listener A [ClickableListListener] to bind interactions to. */ @@ -76,6 +79,7 @@ class ArtistChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/picker/ArtistNavigationPickerDialog.kt b/app/src/main/java/org/oxycblt/auxio/picker/ArtistNavigationPickerDialog.kt index e998e9976..ff55b9c29 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/ArtistNavigationPickerDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/ArtistNavigationPickerDialog.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.ui.NavigationViewModel /** * An [ArtistPickerDialog] intended for when [Artist] navigation is ambiguous. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/picker/ArtistPickerDialog.kt b/app/src/main/java/org/oxycblt/auxio/picker/ArtistPickerDialog.kt index a4a57eda2..18136c1ae 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/ArtistPickerDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/ArtistPickerDialog.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.util.collectImmediately * The base class for dialogs that implements common behavior across all [Artist] pickers. These are * shown whenever what to do with an item's [Artist] is ambiguous, as there are multiple [Artist]'s * to choose from. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/picker/ArtistPlaybackPickerDialog.kt b/app/src/main/java/org/oxycblt/auxio/picker/ArtistPlaybackPickerDialog.kt index ea1916fda..421b28773 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/ArtistPlaybackPickerDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/ArtistPlaybackPickerDialog.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * An [ArtistPickerDialog] intended for when [Artist] playback is ambiguous. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/picker/GenreChoiceAdapter.kt b/app/src/main/java/org/oxycblt/auxio/picker/GenreChoiceAdapter.kt index 2cea397b5..5432643fb 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/GenreChoiceAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/GenreChoiceAdapter.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.inflater /** * An [RecyclerView.Adapter] that displays a list of [Genre] choices. + * * @param listener A [ClickableListListener] to bind interactions to. * @author OxygenCobalt. */ @@ -46,6 +47,7 @@ class GenreChoiceAdapter(private val listener: ClickableListListener) : /** * Immediately update the [Genre] choices. + * * @param newGenres The new [Genre]s to show. */ fun submitList(newGenres: List) { @@ -64,6 +66,7 @@ class GenreChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : DialogRecyclerView.ViewHolder(binding.root) { /** * Bind new data to this instance. + * * @param genre The new [Genre] to bind. * @param listener A [ClickableListListener] to bind interactions to. */ @@ -76,6 +79,7 @@ class GenreChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/picker/GenrePlaybackPickerDialog.kt b/app/src/main/java/org/oxycblt/auxio/picker/GenrePlaybackPickerDialog.kt index 81e5607b7..1ba8965ea 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/GenrePlaybackPickerDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/GenrePlaybackPickerDialog.kt @@ -39,6 +39,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A picker [ViewBindingDialogFragment] intended for when [Genre] playback is ambiguous. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/picker/PickerViewModel.kt b/app/src/main/java/org/oxycblt/auxio/picker/PickerViewModel.kt index 800f069ad..9bc85126b 100644 --- a/app/src/main/java/org/oxycblt/auxio/picker/PickerViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/picker/PickerViewModel.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * a [ViewModel] that manages the current music picker state. Make it so that the dialogs just * contain the music themselves and then exit if the library changes. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -62,6 +63,7 @@ class PickerViewModel @Inject constructor(private val musicRepository: MusicRepo /** * Set a new [currentItem] from it's [Music.UID]. + * * @param uid The [Music.UID] of the [Song] to update to. */ fun setItemUid(uid: Music.UID) { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt index f1130b5dc..b12d4845e 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt @@ -22,6 +22,7 @@ import org.oxycblt.auxio.IntegerTable /** * Represents a configuration option for what kind of "secondary" action to show in a particular UI * context. + * * @author Alexander Capehart (OxygenCobalt) */ enum class ActionMode { @@ -34,6 +35,7 @@ enum class ActionMode { /** * The integer representation of this instance. + * * @see fromIntCode */ val intCode: Int @@ -47,6 +49,7 @@ enum class ActionMode { companion object { /** * Convert a [ActionMode] integer representation into an instance. + * * @param intCode An integer representation of a [ActionMode] * @return The corresponding [ActionMode], or null if the [ActionMode] is invalid. * @see ActionMode.intCode 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 5ecf71d21..a92ff1f1b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.util.getColorCompat /** * A [ViewBindingFragment] that shows the current playback state in a compact manner. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBottomSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBottomSheetBehavior.kt index fcb07e937..c22149e94 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBottomSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBottomSheetBehavior.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.getDimen /** * The [BaseBottomSheetBehavior] for the playback bottom sheet. This bottom sheet + * * @author Alexander Capehart (OxygenCobalt) */ class PlaybackBottomSheetBehavior(context: Context, attributeSet: AttributeSet?) : 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 49f018f85..39083677c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -47,6 +47,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [ViewBindingFragment] more information about the currently playing song, alongside all * available controls. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt index 218c83b89..e642f0ada 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.util.logD /** * User configuration specific to the playback system. + * * @author Alexander Capehart (OxygenCobalt) */ interface PlaybackSettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt index 5872e2f41..7cd3ed29d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt @@ -21,52 +21,60 @@ import android.text.format.DateUtils /** * Convert milliseconds into deci-seconds (1/10th of a second). + * * @return A converted deci-second value. */ fun Long.msToDs() = floorDiv(100) /** * Convert milliseconds into seconds. + * * @return A converted second value. */ fun Long.msToSecs() = floorDiv(1000) /** * Convert deci-seconds (1/10th of a second) into milliseconds. + * * @return A converted millisecond value. */ fun Long.dsToMs() = times(100) /** * Convert deci-seconds (1/10th of a second) into seconds. + * * @return A converted second value. */ fun Long.dsToSecs() = floorDiv(10) /** * Convert seconds into milliseconds. + * * @return A converted millisecond value. */ fun Long.secsToMs() = times(1000) /** * Convert a millisecond value into a string duration. + * * @param isElapsed Whether this duration is represents elapsed time. If this is false, then --:-- - * will be returned if the second value is 0. + * will be returned if the second value is 0. */ fun Long.formatDurationMs(isElapsed: Boolean) = msToSecs().formatDurationSecs(isElapsed) /** * // * Format a deci-second value (1/10th of a second) into a string duration. + * * @param isElapsed Whether this duration is represents elapsed time. If this is false, then --:-- - * will be returned if the second value is 0. + * will be returned if the second value is 0. */ fun Long.formatDurationDs(isElapsed: Boolean) = dsToSecs().formatDurationSecs(isElapsed) /** * Convert a second value into a string duration. + * * @param isElapsed Whether this duration is represents elapsed time. If this is false, then --:-- - * will be returned if the second value is 0. + * will be returned if the second value is 0. */ fun Long.formatDurationSecs(isElapsed: Boolean): String { if (!isElapsed && this == 0L) { 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 82b6a8fdd..9e0af6490 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.playback.state.* /** * An [ViewModel] that provides a safe UI frontend for the current playback state. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -76,6 +77,7 @@ constructor( /** * Flag signaling to open a picker dialog in order to resolve an ambiguous choice when playing a * [Song] from one of it's [Artist]s. + * * @see playFromArtist */ val artistPickerSong: StateFlow @@ -163,6 +165,7 @@ constructor( * - If [MusicMode.ALBUMS], the [Song] is played from it's [Album]. * - If [MusicMode.ARTISTS], the [Song] is played from one of it's [Artist]s. * - If [MusicMode.GENRES], the [Song] is played from one of it's [Genre]s. + * * @param song The [Song] to play. * @param playbackMode The [MusicMode] to play from. */ @@ -177,9 +180,10 @@ constructor( /** * Play a [Song] from one of it's [Artist]s. + * * @param song The [Song] to play. * @param artist The [Artist] to play from. Must be linked to the [Song]. If null, the user will - * be prompted on what artist to play. Defaults to null. + * be prompted on what artist to play. Defaults to null. */ fun playFromArtist(song: Song, artist: Artist? = null) { if (artist != null) { @@ -194,6 +198,7 @@ constructor( /** * Mark the [Artist] playback choice process as complete. This should occur when the [Artist] * choice dialog is opened after this flag is detected. + * * @see playFromArtist */ fun finishPlaybackArtistPicker() { @@ -202,9 +207,10 @@ constructor( /** * PLay a [Song] from one of it's [Genre]s. + * * @param song The [Song] to play. * @param genre The [Genre] to play from. Must be linked to the [Song]. If null, the user will - * be prompted on what artist to play. Defaults to null. + * be prompted on what artist to play. Defaults to null. */ fun playFromGenre(song: Song, genre: Genre? = null) { if (genre != null) { @@ -219,6 +225,7 @@ constructor( /** * Mark the [Genre] playback choice process as complete. This should occur when the [Genre] * choice dialog is opened after this flag is detected. + * * @see playFromGenre */ fun finishPlaybackGenrePicker() { @@ -227,24 +234,28 @@ constructor( /** * Play an [Album]. + * * @param album The [Album] to play. */ fun play(album: Album) = playImpl(null, album, false) /** * Play an [Artist]. + * * @param artist The [Artist] to play. */ fun play(artist: Artist) = playImpl(null, artist, false) /** * Play a [Genre]. + * * @param genre The [Genre] to play. */ fun play(genre: Genre) = playImpl(null, genre, false) /** * Play a [Music] selection. + * * @param selection The selection to play. */ fun play(selection: List) = @@ -252,24 +263,28 @@ constructor( /** * Shuffle an [Album]. + * * @param album The [Album] to shuffle. */ fun shuffle(album: Album) = playImpl(null, album, true) /** * Shuffle an [Artist]. + * * @param artist The [Artist] to shuffle. */ fun shuffle(artist: Artist) = playImpl(null, artist, true) /** * Shuffle an [Genre]. + * * @param genre The [Genre] to shuffle. */ fun shuffle(genre: Genre) = playImpl(null, genre, true) /** * Shuffle a [Music] selection. + * * @param selection The selection to shuffle. */ fun shuffle(selection: List) = @@ -298,6 +313,7 @@ constructor( /** * Start the given [InternalPlayer.Action] to be completed eventually. This can be used to * enqueue a playback action at startup to then occur when the music library is fully loaded. + * * @param action The [InternalPlayer.Action] to perform eventually. */ fun startAction(action: InternalPlayer.Action) { @@ -308,6 +324,7 @@ constructor( /** * Seek to the given position in the currently playing [Song]. + * * @param positionDs The position to seek to, in deci-seconds (1/10th of a second). */ fun seekTo(positionDs: Long) { @@ -328,6 +345,7 @@ constructor( /** * Add a [Song] to the top of the queue. + * * @param song The [Song] to add. */ fun playNext(song: Song) { @@ -336,6 +354,7 @@ constructor( /** * Add a [Album] to the top of the queue. + * * @param album The [Album] to add. */ fun playNext(album: Album) { @@ -344,6 +363,7 @@ constructor( /** * Add a [Artist] to the top of the queue. + * * @param artist The [Artist] to add. */ fun playNext(artist: Artist) { @@ -352,6 +372,7 @@ constructor( /** * Add a [Genre] to the top of the queue. + * * @param genre The [Genre] to add. */ fun playNext(genre: Genre) { @@ -360,6 +381,7 @@ constructor( /** * Add a selection to the top of the queue. + * * @param selection The [Music] selection to add. */ fun playNext(selection: List) { @@ -368,6 +390,7 @@ constructor( /** * Add a [Song] to the end of the queue. + * * @param song The [Song] to add. */ fun addToQueue(song: Song) { @@ -376,6 +399,7 @@ constructor( /** * Add a [Album] to the end of the queue. + * * @param album The [Album] to add. */ fun addToQueue(album: Album) { @@ -384,6 +408,7 @@ constructor( /** * Add a [Artist] to the end of the queue. + * * @param artist The [Artist] to add. */ fun addToQueue(artist: Artist) { @@ -392,6 +417,7 @@ constructor( /** * Add a [Genre] to the end of the queue. + * * @param genre The [Genre] to add. */ fun addToQueue(genre: Genre) { @@ -400,6 +426,7 @@ constructor( /** * Add a selection to the end of the queue. + * * @param selection The [Music] selection to add. */ fun addToQueue(selection: List) { @@ -420,6 +447,7 @@ constructor( /** * Toggle [repeatMode] (ex. from [RepeatMode.NONE] to [RepeatMode.TRACK]) + * * @see RepeatMode.increment */ fun toggleRepeatMode() { @@ -430,6 +458,7 @@ constructor( /** * Force-save the current playback state. + * * @param onDone Called when the save is completed with true if successful, and false otherwise. */ fun savePlaybackState(onDone: (Boolean) -> Unit) { @@ -440,6 +469,7 @@ constructor( /** * Clear the current playback state. + * * @param onDone Called when the wipe is completed with true if successful, and false otherwise. */ fun wipePlaybackState(onDone: (Boolean) -> Unit) { @@ -448,8 +478,9 @@ constructor( /** * Force-restore the current playback state. + * * @param onDone Called when the restoration is completed with true if successful, and false - * otherwise. + * otherwise. */ fun tryRestorePlaybackState(onDone: (Boolean) -> Unit) { viewModelScope.launch { @@ -468,9 +499,10 @@ constructor( /** * Convert the given selection to a list of [Song]s. + * * @param selection The selection of [Music] to convert. * @return A [Song] list containing the child items of any [MusicParent] instances in the list - * alongside the unchanged [Song]s or the original selection. + * alongside the unchanged [Song]s or the original selection. */ private fun selectionToSongs(selection: List): List { return selection.flatMap { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceDatabase.kt b/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceDatabase.kt index be41d0413..a92947137 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceDatabase.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceDatabase.kt @@ -32,6 +32,7 @@ import org.oxycblt.auxio.playback.state.RepeatMode /** * Provides raw access to the database storing the persisted playback state. + * * @author Alexander Capehart */ @Database( @@ -42,12 +43,14 @@ import org.oxycblt.auxio.playback.state.RepeatMode abstract class PersistenceDatabase : RoomDatabase() { /** * Get the current [PlaybackStateDao]. + * * @return A [PlaybackStateDao] providing control of the database's playback state tables. */ abstract fun playbackStateDao(): PlaybackStateDao /** * Get the current [QueueDao]. + * * @return A [QueueDao] providing control of the database's queue tables. */ abstract fun queueDao(): QueueDao @@ -63,12 +66,14 @@ abstract class PersistenceDatabase : RoomDatabase() { /** * Provides control of the persisted playback state table. + * * @author Alexander Capehart (OxygenCobalt) */ @Dao interface PlaybackStateDao { /** * Get the previously persisted [PlaybackState]. + * * @return The previously persisted [PlaybackState], or null if one was not present. */ @Query("SELECT * FROM ${PlaybackState.TABLE_NAME} WHERE id = 0") @@ -79,6 +84,7 @@ interface PlaybackStateDao { /** * Insert a new [PlaybackState] into the database. + * * @param state The [PlaybackState] to insert. */ @Insert(onConflict = OnConflictStrategy.ABORT) suspend fun insertState(state: PlaybackState) @@ -86,18 +92,21 @@ interface PlaybackStateDao { /** * Provides control of the persisted queue state tables. + * * @author Alexander Capehart (OxygenCobalt) */ @Dao interface QueueDao { /** * Get the previously persisted queue heap. + * * @return A list of persisted [QueueHeapItem]s wrapping each heap item. */ @Query("SELECT * FROM ${QueueHeapItem.TABLE_NAME}") suspend fun getHeap(): List /** * Get the previously persisted queue mapping. + * * @return A list of persisted [QueueMappingItem]s wrapping each heap item. */ @Query("SELECT * FROM ${QueueMappingItem.TABLE_NAME}") @@ -111,12 +120,14 @@ interface QueueDao { /** * Insert new heap entries into the database. + * * @param heap The list of wrapped [QueueHeapItem]s to insert. */ @Insert(onConflict = OnConflictStrategy.ABORT) suspend fun insertHeap(heap: List) /** * Insert new mapping entries into the database. + * * @param mapping The list of wrapped [QueueMappingItem] to insert. */ @Insert(onConflict = OnConflictStrategy.ABORT) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceRepository.kt b/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceRepository.kt index 854906036..4244f6096 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/persist/PersistenceRepository.kt @@ -27,17 +27,20 @@ import org.oxycblt.auxio.util.logE /** * Manages the persisted playback state in a structured manner. + * * @author Alexander Capehart (OxygenCobalt) */ interface PersistenceRepository { /** * Read the previously persisted [PlaybackStateManager.SavedState]. + * * @param library The [Library] required to de-serialize the [PlaybackStateManager.SavedState]. */ suspend fun readState(library: Library): PlaybackStateManager.SavedState? /** * Persist a new [PlaybackStateManager.SavedState]. + * * @param state The [PlaybackStateManager.SavedState] to persist. */ suspend fun saveState(state: PlaybackStateManager.SavedState?): Boolean diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/Queue.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/Queue.kt index 9a2b44eb9..87267d496 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/Queue.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/Queue.kt @@ -45,6 +45,7 @@ interface Queue { val isShuffled: Boolean /** * Resolve this queue into a more conventional list of [Song]s. + * * @return A list of [Song] corresponding to the current queue mapping. */ fun resolve(): List @@ -67,9 +68,10 @@ interface Queue { /** * An immutable representation of the queue state. + * * @param heap The heap of [Song]s that are/were used in the queue. This can be modified with - * null values to represent [Song]s that were "lost" from the heap without having to change - * other values. + * null values to represent [Song]s that were "lost" from the heap without having to change + * other values. * @param orderedMapping The mapping of the [heap] to an ordered queue. * @param shuffledMapping The mapping of the [heap] to a shuffled queue. * @param index The index of the currently playing [Song] at the time of serialization. @@ -85,9 +87,10 @@ interface Queue { /** * Remaps the [heap] of this instance based on the given mapping function and copies it into * a new [SavedState]. + * * @param transform Code to remap the existing [Song] heap into a new [Song] heap. This - * **MUST** be the same size as the original heap. [Song] instances that could not be - * converted should be replaced with null in the new heap. + * **MUST** be the same size as the original heap. [Song] instances that could not be + * converted should be replaced with null in the new heap. * @throws IllegalStateException If the invariant specified by [transform] is violated. */ inline fun remap(transform: (Song?) -> Song?) = @@ -121,6 +124,7 @@ class EditableQueue : Queue { /** * Go to a particular index in the queue. + * * @param to The index of the [Song] to start playing, in the current queue mapping. * @return true if the queue jumped to that position, false otherwise. */ @@ -134,11 +138,12 @@ class EditableQueue : Queue { /** * Start a new queue configuration. + * * @param play The [Song] to play, or null to start from a random position. * @param queue The queue of [Song]s to play. Must contain [play]. This list will become the - * heap internally. + * heap internally. * @param shuffled Whether to shuffle the queue or not. This changes the interpretation of - * [queue]. + * [queue]. */ fun start(play: Song?, queue: List, shuffled: Boolean) { heap = queue.toMutableList() @@ -152,6 +157,7 @@ class EditableQueue : Queue { /** * Re-order the queue. + * * @param shuffled Whether the queue should be shuffled or not. */ fun reorder(shuffled: Boolean) { @@ -185,10 +191,11 @@ class EditableQueue : Queue { /** * Add [Song]s to the top of the queue. Will start playback if nothing is playing. + * * @param songs The [Song]s to add. * @return [Queue.ChangeResult.MAPPING] if added to an existing queue, or - * [Queue.ChangeResult.SONG] if there was no prior playback and these enqueued [Song]s start new - * playback. + * [Queue.ChangeResult.SONG] if there was no prior playback and these enqueued [Song]s start + * new playback. */ fun playNext(songs: List): Queue.ChangeResult { if (orderedMapping.isEmpty()) { @@ -214,10 +221,11 @@ class EditableQueue : Queue { /** * Add [Song]s to the end of the queue. Will start playback if nothing is playing. + * * @param songs The [Song]s to add. * @return [Queue.ChangeResult.MAPPING] if added to an existing queue, or - * [Queue.ChangeResult.SONG] if there was no prior playback and these enqueued [Song]s start new - * playback. + * [Queue.ChangeResult.SONG] if there was no prior playback and these enqueued [Song]s start + * new playback. */ fun addToQueue(songs: List): Queue.ChangeResult { if (orderedMapping.isEmpty()) { @@ -238,11 +246,12 @@ class EditableQueue : Queue { /** * Move a [Song] at the given position to a new position. + * * @param src The position of the [Song] to move. * @param dst The destination position of the [Song]. * @return [Queue.ChangeResult.MAPPING] if the move occurred after the current index, - * [Queue.ChangeResult.INDEX] if the move occurred before or at the current index, requiring it - * to be mutated. + * [Queue.ChangeResult.INDEX] if the move occurred before or at the current index, requiring + * it to be mutated. */ fun move(src: Int, dst: Int): Queue.ChangeResult { if (shuffledMapping.isNotEmpty()) { @@ -273,10 +282,11 @@ class EditableQueue : Queue { /** * Remove a [Song] at the given position. + * * @param at The position of the [Song] to remove. * @return [Queue.ChangeResult.MAPPING] if the removed [Song] was after the current index, - * [Queue.ChangeResult.INDEX] if the removed [Song] was before the current index, and - * [Queue.ChangeResult.SONG] if the currently playing [Song] was removed. + * [Queue.ChangeResult.INDEX] if the removed [Song] was before the current index, and + * [Queue.ChangeResult.SONG] if the currently playing [Song] was removed. */ fun remove(at: Int): Queue.ChangeResult { if (shuffledMapping.isNotEmpty()) { @@ -311,6 +321,7 @@ class EditableQueue : Queue { /** * Convert the current state of this instance into a [Queue.SavedState]. + * * @return A new [Queue.SavedState] reflecting the exact state of the queue when called. */ fun toSavedState() = @@ -321,6 +332,7 @@ class EditableQueue : Queue { /** * Update this instance from the given [Queue.SavedState]. + * * @param savedState A [Queue.SavedState] with a valid queue representation. */ fun applySavedState(savedState: Queue.SavedState) { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index 2b67c5b3e..c83aaf263 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -38,6 +38,7 @@ import org.oxycblt.auxio.util.* /** * A [RecyclerView.Adapter] that shows an editable list of queue items. + * * @param listener A [EditableListListener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -72,6 +73,7 @@ class QueueAdapter(private val listener: EditableListListener) : /** * Set the position of the currently playing item in the queue. This will mark the item as * playing and any previous items as played. + * * @param index The position of the currently playing item in the queue. * @param isPlaying Whether playback is ongoing or paused. */ @@ -99,6 +101,7 @@ class QueueAdapter(private val listener: EditableListListener) : /** * A [PlayingIndicatorAdapter.ViewHolder] that displays a queue [Song]. Use [from] to create an * instance. + * * @author Alexander Capehart (OxygenCobalt) */ class QueueSongViewHolder private constructor(private val binding: ItemQueueSongBinding) : @@ -142,6 +145,7 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong /** * Bind new data to this instance. + * * @param song The new [Song] to bind. * @param listener A [EditableListListener] to bind interactions to. */ @@ -164,6 +168,7 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt index 9796cdc34..89558fa6d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueBottomSheetBehavior.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * The [BaseBottomSheetBehavior] for the queue bottom sheet. This is placed within the playback * sheet and automatically arranges itself to show the playback bar at the top. + * * @author Alexander Capehart (OxygenCobalt) */ class QueueBottomSheetBehavior(context: Context, attributeSet: AttributeSet?) : diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt index c8308ef70..7a54c14e2 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueDragCallback.kt @@ -31,9 +31,9 @@ import org.oxycblt.auxio.util.logD * A highly customized [ItemTouchHelper.Callback] that enables some extra eye candy in the queue UI, * such as an animation when lifting items. * - * TODO: Why is item movement so expensive??? - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Why is item movement so expensive??? */ class QueueDragCallback(private val playbackModel: QueueViewModel) : ItemTouchHelper.Callback() { private var shouldLift = true diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt index 0e71bb55f..753503825 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt @@ -36,6 +36,7 @@ import org.oxycblt.auxio.util.collectImmediately /** * A [ViewBindingFragment] that displays an editable queue. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt index 1e09a1bbf..8e42063fb 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueViewModel.kt @@ -88,8 +88,9 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt /** * Start playing the the queue item at the given index. + * * @param adapterIndex The index of the queue item to play. Does nothing if the index is out of - * range. + * range. */ fun goto(adapterIndex: Int) { playbackManager.goto(adapterIndex) @@ -97,8 +98,9 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt /** * Remove a queue item at the given index. + * * @param adapterIndex The index of the queue item to play. Does nothing if the index is out of - * range. + * range. */ fun removeQueueDataItem(adapterIndex: Int) { if (adapterIndex !in queue.value.indices) { @@ -109,6 +111,7 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt /** * Move a queue item from one index to another index. + * * @param adapterFrom The index of the queue item to move. * @param adapterTo The destination index for the queue item. * @return true if the items were moved, false otherwise. diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/PreAmpCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/PreAmpCustomizeDialog.kt index 81db4bad3..04e2834d3 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/PreAmpCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/PreAmpCustomizeDialog.kt @@ -31,6 +31,7 @@ import org.oxycblt.auxio.ui.ViewBindingDialogFragment /** * aa [ViewBindingDialogFragment] that allows user configuration of the current [ReplayGainPreAmp]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGain.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGain.kt index c10dae5a3..b57d8d2c6 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGain.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGain.kt @@ -21,6 +21,7 @@ import org.oxycblt.auxio.IntegerTable /** * The current ReplayGain configuration. + * * @author Alexander Capehart (OxygenCobalt) */ enum class ReplayGainMode { @@ -34,6 +35,7 @@ enum class ReplayGainMode { companion object { /** * Convert a [ReplayGainMode] integer representation into an instance. + * * @param intCode An integer representation of a [ReplayGainMode] * @return The corresponding [ReplayGainMode], or null if the [ReplayGainMode] is invalid. */ @@ -49,6 +51,7 @@ enum class ReplayGainMode { /** * The current ReplayGain pre-amp configuration. + * * @param with The pre-amp (in dB) to use when ReplayGain tags are present. * @param without The pre-amp (in dB) to use when ReplayGain tags are not present. * @author Alexander Capehart (OxygenCobalt) 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 d8fbc08d5..14a06117c 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 @@ -59,8 +59,9 @@ constructor( /** * Add this instance to the components required for it to function correctly. + * * @param player The [Player] to attach to. Should already have this instance as an audio - * processor. + * processor. */ fun addToListeners(player: Player) { player.addListener(this) @@ -69,8 +70,9 @@ constructor( /** * Remove this instance from the components required for it to function correctly. + * * @param player The [Player] to detach from. Should already have this instance as an audio - * processor. + * processor. */ fun releaseFromListeners(player: Player) { player.removeListener(this) @@ -106,6 +108,7 @@ constructor( /** * Updates the volume adjustment based on the given [Format]. + * * @param format The [Format] of the currently playing track, or null if nothing is playing. */ private fun applyReplayGain(format: Format?) { @@ -157,6 +160,7 @@ constructor( /** * Parse ReplayGain information from the given [Format]. + * * @param format The [Format] to parse. * @return A [Adjustment] adjustment, or null if there were no valid adjustments. */ @@ -199,6 +203,7 @@ constructor( /** * Parse a ReplayGain adjustment into a float value. + * * @return A parsed adjustment float, or null if the adjustment had invalid formatting. */ private fun String.parseReplayGainAdjustment() = @@ -254,6 +259,7 @@ constructor( /** * Always read a little-endian [Short] from the [ByteBuffer] at the given index. + * * @param at The index to read the [Short] from. */ private fun ByteBuffer.getLeShort(at: Int) = @@ -261,6 +267,7 @@ constructor( /** * Always write a little-endian [Short] at the end of the [ByteBuffer]. + * * @param short The [Short] to write. */ private fun ByteBuffer.putLeShort(short: Short) { @@ -270,6 +277,7 @@ constructor( /** * The resolved ReplayGain adjustment for a file. + * * @param track The track adjustment (in dB), or 0 if it is not present. * @param album The album adjustment (in dB), or 0 if it is not present. */ diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt index 7c2487458..9205ffb60 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt @@ -25,6 +25,7 @@ import org.oxycblt.auxio.music.Song /** * An interface for internal audio playback. This can be used to coordinate what occurs in the * background playback task. + * * @author Alexander Capehart (OxygenCobalt) */ interface InternalPlayer { @@ -36,6 +37,7 @@ interface InternalPlayer { /** * Load a new [Song] into the internal player. + * * @param song The [Song] to load, or null if playback should stop entirely. * @param play Whether to start playing when the [Song] is loaded. */ @@ -43,6 +45,7 @@ interface InternalPlayer { /** * Called when an [Action] has been queued and this [InternalPlayer] is available to handle it. + * * @param action The [Action] to perform. * @return true if the action was handled, false otherwise. */ @@ -50,19 +53,22 @@ interface InternalPlayer { /** * Get a [State] corresponding to the current player state. + * * @param durationMs The duration of the currently playing track, in milliseconds. Required - * since the internal player cannot obtain an accurate duration itself. + * since the internal player cannot obtain an accurate duration itself. */ fun getState(durationMs: Long): State /** * Seek to a given position in the internal player. + * * @param positionMs The position to seek to, in milliseconds. */ fun seekTo(positionMs: Long) /** * Set whether the player should play or not. + * * @param isPlaying Whether to play or pause the current playback. */ fun setPlaying(isPlaying: Boolean) @@ -80,6 +86,7 @@ interface InternalPlayer { /** * Start playing an audio file at the given [Uri]. + * * @param uri The [Uri] of the audio file to start playing. */ data class Open(val uri: Uri) : Action() @@ -101,8 +108,9 @@ interface InternalPlayer { ) { /** * Calculate the "real" playback position this instance contains, in milliseconds. + * * @return If paused, the original position will be returned. Otherwise, it will be the - * original position plus the time elapsed since this state was created. + * original position plus the time elapsed since this state was created. */ fun calculateElapsedPositionMs() = if (isAdvancing) { @@ -115,6 +123,7 @@ interface InternalPlayer { /** * Load this instance into a [PlaybackStateCompat]. + * * @param builder The [PlaybackStateCompat.Builder] to mutate. * @return The same [PlaybackStateCompat.Builder] for easy chaining. */ @@ -155,8 +164,9 @@ interface InternalPlayer { companion object { /** * Create a new instance. + * * @param isPlaying Whether the player is actively playing audio or set to play audio in - * the future. + * the future. * @param isAdvancing Whether the player is actively playing audio in this moment. * @param positionMs The current position of the player. */ diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index f00182b53..30362bb9c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -34,9 +34,9 @@ import org.oxycblt.auxio.util.logW * * This should ***NOT*** be used outside of the playback module. * - If you want to use the playback state in the UI, use PlaybackViewModel as it can withstand - * volatile UIs. + * volatile UIs. * - If you want to use the playback state with the ExoPlayer instance or system-side things, use - * PlaybackService. + * PlaybackService. * * Internal consumers should usually use [Listener], however the component that manages the player * itself should instead use [InternalPlayer]. @@ -58,6 +58,7 @@ interface PlaybackStateManager { /** * Add a [Listener] to this instance. This can be used to receive changes in the playback state. * Will immediately invoke [Listener] methods to initialize the instance with the current state. + * * @param listener The [Listener] to add. * @see Listener */ @@ -65,8 +66,9 @@ interface PlaybackStateManager { /** * Remove a [Listener] from this instance, preventing it from receiving any further updates. + * * @param listener The [Listener] to remove. Does nothing if the [Listener] was never added in - * the first place. + * the first place. * @see Listener */ fun removeListener(listener: Listener) @@ -75,25 +77,28 @@ interface PlaybackStateManager { * Register an [InternalPlayer] for this instance. This instance will handle translating the * current playback state into audio playback. There can be only one [InternalPlayer] at a time. * Will invoke [InternalPlayer] methods to initialize the instance with the current state. + * * @param internalPlayer The [InternalPlayer] to register. Will do nothing if already - * registered. + * registered. */ fun registerInternalPlayer(internalPlayer: InternalPlayer) /** * Unregister the [InternalPlayer] from this instance, prevent it from receiving any further * commands. + * * @param internalPlayer The [InternalPlayer] to unregister. Must be the current - * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. + * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. */ fun unregisterInternalPlayer(internalPlayer: InternalPlayer) /** * Start new playback. + * * @param song A particular [Song] to play, or null to play the first [Song] in the new queue. * @param queue The queue of [Song]s to play from. * @param parent The [MusicParent] to play from, or null if to play from an non-specific - * collection of "All [Song]s". + * collection of "All [Song]s". * @param shuffled Whether to shuffle or not. */ fun play(song: Song?, parent: MusicParent?, queue: List, shuffled: Boolean) @@ -112,36 +117,42 @@ interface PlaybackStateManager { /** * Play a [Song] at the given position in the queue. + * * @param index The position of the [Song] in the queue to start playing. */ fun goto(index: Int) /** * Add [Song]s to the top of the queue. + * * @param songs The [Song]s to add. */ fun playNext(songs: List) /** * Add a [Song] to the top of the queue. + * * @param song The [Song] to add. */ fun playNext(song: Song) = playNext(listOf(song)) /** * Add [Song]s to the end of the queue. + * * @param songs The [Song]s to add. */ fun addToQueue(songs: List) /** * Add a [Song] to the end of the queue. + * * @param song The [Song] to add. */ fun addToQueue(song: Song) = addToQueue(listOf(song)) /** * Move a [Song] in the queue. + * * @param src The position of the [Song] to move in the queue. * @param dst The destination position in the queue. */ @@ -149,25 +160,29 @@ interface PlaybackStateManager { /** * Remove a [Song] from the queue. + * * @param at The position of the [Song] to remove in the queue. */ fun removeQueueItem(at: Int) /** * (Re)shuffle or (Re)order this instance. + * * @param shuffled Whether to shuffle the queue or not. */ fun reorder(shuffled: Boolean) /** * Synchronize the state of this instance with the current [InternalPlayer]. + * * @param internalPlayer The [InternalPlayer] to synchronize with. Must be the current - * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. + * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. */ fun synchronizeState(internalPlayer: InternalPlayer) /** * Start a [InternalPlayer.Action] for the current [InternalPlayer] to handle eventually. + * * @param action The [InternalPlayer.Action] to perform. */ fun startAction(action: InternalPlayer.Action) @@ -175,19 +190,22 @@ interface PlaybackStateManager { /** * Request that the pending [InternalPlayer.Action] (if any) be passed to the given * [InternalPlayer]. + * * @param internalPlayer The [InternalPlayer] to synchronize with. Must be the current - * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. + * [InternalPlayer]. Does nothing if invoked by another [InternalPlayer] implementation. */ fun requestAction(internalPlayer: InternalPlayer) /** * Update whether playback is ongoing or not. + * * @param isPlaying Whether playback is ongoing or not. */ fun setPlaying(isPlaying: Boolean) /** * Seek to the given position in the currently playing [Song]. + * * @param positionMs The position to seek to, in milliseconds. */ fun seekTo(positionMs: Long) @@ -197,16 +215,18 @@ interface PlaybackStateManager { /** * Converts the current state of this instance into a [SavedState]. + * * @return An immutable [SavedState] that is analogous to the current state, or null if nothing - * is currently playing. + * is currently playing. */ fun toSavedState(): SavedState? /** * Restores this instance from the given [SavedState]. + * * @param savedState The [SavedState] to restore from. * @param destructive Whether to disregard the prior playback state and overwrite it with this - * [SavedState]. + * [SavedState]. */ fun applySavedState(savedState: SavedState, destructive: Boolean) @@ -218,12 +238,14 @@ interface PlaybackStateManager { /** * Called when the position of the currently playing item has changed, changing the current * [Song], but no other queue attribute has changed. + * * @param queue The new [Queue]. */ fun onIndexMoved(queue: Queue) {} /** * Called when the [Queue] changed in a manner outlined by the given [Queue.ChangeResult]. + * * @param queue The new [Queue]. * @param change The type of [Queue.ChangeResult] that occurred. */ @@ -232,12 +254,14 @@ interface PlaybackStateManager { /** * Called when the [Queue] has changed in a non-trivial manner (such as re-shuffling), but * the currently playing [Song] has not. + * * @param queue The new [Queue]. */ fun onQueueReordered(queue: Queue) {} /** * Called when a new playback configuration was created. + * * @param queue The new [Queue]. * @param parent The new [MusicParent] being played from, or null if playing from all songs. */ @@ -245,12 +269,14 @@ interface PlaybackStateManager { /** * Called when the state of the [InternalPlayer] changes. + * * @param state The new state of the [InternalPlayer]. */ fun onStateChanged(state: InternalPlayer.State) {} /** * Called when the [RepeatMode] changes. + * * @param repeatMode The new [RepeatMode]. */ fun onRepeatChanged(repeatMode: RepeatMode) {} @@ -258,6 +284,7 @@ interface PlaybackStateManager { /** * A condensed representation of the playback state that can be persisted. + * * @param parent The [MusicParent] item currently being played from. * @param queueState The [Queue.SavedState] * @param positionMs The current position in the currently played song, in ms diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/RepeatMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/RepeatMode.kt index e4da1aa72..e521a199d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/RepeatMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/RepeatMode.kt @@ -22,6 +22,7 @@ import org.oxycblt.auxio.R /** * Represents the current repeat mode of the player. + * * @author Alexander Capehart (OxygenCobalt) */ enum class RepeatMode { @@ -44,6 +45,7 @@ enum class RepeatMode { /** * Increment the mode. + * * @return If [NONE], [ALL]. If [ALL], [TRACK]. If [TRACK], [NONE]. */ fun increment() = @@ -55,6 +57,7 @@ enum class RepeatMode { /** * The integer representation of this instance. + * * @see fromIntCode */ val icon: Int @@ -77,6 +80,7 @@ enum class RepeatMode { companion object { /** * Convert a [RepeatMode] integer representation into an instance. + * * @param intCode An integer representation of a [RepeatMode] * @return The corresponding [RepeatMode], or null if the [RepeatMode] is invalid. * @see RepeatMode.intCode diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/BluetoothHeadsetReceiver.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/BluetoothHeadsetReceiver.kt index 667d7c3ce..af4e0331a 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/BluetoothHeadsetReceiver.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/BluetoothHeadsetReceiver.kt @@ -24,6 +24,7 @@ import android.content.Intent /** * A [BroadcastReceiver] that starts music playback when a bluetooth headset is connected. + * * @author seijikun, OxygenCobalt */ class BluetoothHeadsetReceiver : BroadcastReceiver() { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt index 02e4ff557..f7be28c00 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaButtonReceiver.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager /** * A [BroadcastReceiver] that forwards [Intent.ACTION_MEDIA_BUTTON] [Intent]s to [PlaybackService]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index c1a099636..d3a0fcb69 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -47,6 +47,7 @@ import org.oxycblt.auxio.util.logD /** * A component that mirrors the current playback state into the [MediaSessionCompat] and * [NotificationComponent]. + * * @author Alexander Capehart (OxygenCobalt) */ class MediaSessionComponent @@ -79,6 +80,7 @@ constructor( /** * Forward a system media button [Intent] to the [MediaSessionCompat]. + * * @param intent The [Intent.ACTION_MEDIA_BUTTON] [Intent] to forward. */ fun handleMediaButtonIntent(intent: Intent) { @@ -87,6 +89,7 @@ constructor( /** * Register a [Listener] for notification updates to this service. + * * @param listener The [Listener] to register. */ fun registerListener(listener: Listener) { @@ -271,10 +274,11 @@ constructor( /** * Upload a new [MediaMetadataCompat] based on the current playback state to the * [MediaSessionCompat] and [NotificationComponent]. + * * @param song The current [Song] to create the [MediaMetadataCompat] from, or null if no [Song] - * is currently playing. + * is currently playing. * @param parent The current [MusicParent] to create the [MediaMetadataCompat] from, or null if - * playback is currently occuring from all songs. + * playback is currently occuring from all songs. */ private fun updateMediaMetadata(song: Song?, parent: MusicParent?) { if (song == null) { @@ -338,6 +342,7 @@ constructor( /** * Upload a new queue to the [MediaSessionCompat]. + * * @param queue The current queue to upload. */ private fun updateQueue(queue: Queue) { @@ -367,8 +372,8 @@ constructor( logD("Updating media session playback state") val state = - // InternalPlayer.State handles position/state information. - playbackManager.playerState + // InternalPlayer.State handles position/state information. + playbackManager.playerState .intoPlaybackState(PlaybackStateCompat.Builder()) .setActions(ACTIONS) // Active queue ID corresponds to the indices we populated prior, use them here. @@ -426,6 +431,7 @@ constructor( interface Listener { /** * Called when the [NotificationComponent] changes, requiring it to be re-posed. + * * @param notification The new [NotificationComponent]. */ fun onPostNotification(notification: NotificationComponent) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt index 21cb16676..9d4a85f77 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/NotificationComponent.kt @@ -36,6 +36,7 @@ import org.oxycblt.auxio.util.newMainPendingIntent /** * The playback notification component. Due to race conditions regarding notification updates, this * component is not self-sufficient. [MediaSessionComponent] should be used instead of manage it. + * * @author Alexander Capehart (OxygenCobalt) */ @SuppressLint("RestrictedApi") @@ -67,6 +68,7 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes /** * Update the currently shown metadata in this notification. + * * @param metadata The [MediaMetadataCompat] to display in this notification. */ fun updateMetadata(metadata: MediaMetadataCompat) { @@ -86,6 +88,7 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes /** * Update the playing state shown in this notification. + * * @param isPlaying Whether playback should be indicated as ongoing or paused. */ fun updatePlaying(isPlaying: Boolean) { @@ -94,6 +97,7 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes /** * Update the secondary action in this notification to show the current [RepeatMode]. + * * @param repeatMode The current [RepeatMode]. */ fun updateRepeatMode(repeatMode: RepeatMode) { @@ -102,6 +106,7 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes /** * Update the secondary action in this notification to show the current shuffle state. + * * @param isShuffled Whether the queue is currently shuffled or not. */ fun updateShuffled(isShuffled: Boolean) { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt index aa4497534..163b35961 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt @@ -71,11 +71,10 @@ import org.oxycblt.auxio.widgets.WidgetProvider * not the source of truth for the state, but rather the means to control system-side playback. Both * of those tasks are what [PlaybackStateManager] is for. * - * TODO: Refactor lifecycle to run completely headless (i.e no activity needed) - * - * TODO: Android Auto - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Refactor lifecycle to run completely headless (i.e no activity needed) + * TODO: Android Auto */ @AndroidEntryPoint class PlaybackService : diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt index a81abaec5..c97e2bf31 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.util.getInteger /** * A [MaterialButton] that automatically morphs from a circle to a squircle shape appearance when * [isActivated] changes. + * * @author Alexander Capehart (OxygenCobalt) */ class AnimatedMaterialButton diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt index 37448989c..406f766a7 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt @@ -26,6 +26,7 @@ import android.widget.FrameLayout * A [FrameLayout] that programmatically overrides the child layout to a left-to-right (LTR) layout * direction. This is useful for "Timeline" elements that Material Design recommends be LTR in all * cases. This layout can only contain one child, to prevent conflicts with other layout components. + * * @author Alexander Capehart (OxygenCobalt) */ open class ForcedLTRFrameLayout 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 8df8662e4..bf179e4d6 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 @@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.logD /** * A wrapper around [Slider] that shows position and duration values and sanitizes input to reduce * crashes from invalid values. + * * @author Alexander Capehart (OxygenCobalt) */ class StyledSeekBar @@ -112,6 +113,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 /** * Called when the internal [Slider] was scrubbed to a new position, requesting that a seek * be performed. + * * @param positionDs The position to seek to, in deci-seconds (1/10th of a second). */ fun onSeekConfirmed(positionDs: Long) diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt index 2ec81b783..113bbdecf 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchAdapter.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.logD /** * An adapter that displays search results. + * * @param listener An [SelectableListListener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt index d52b9ef9c..162c4ca3e 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt @@ -29,11 +29,13 @@ import org.oxycblt.auxio.music.Song /** * Implements the fuzzy-ish searching algorithm used in the search view. + * * @author Alexander Capehart */ interface SearchEngine { /** * Begin a search. + * * @param items The items to search over. * @param query The query to search for. * @return A list of items filtered by the given query. @@ -42,6 +44,7 @@ interface SearchEngine { /** * Input/output data to use with [SearchEngine]. + * * @param songs A list of [Song]s, null if empty. * @param albums A list of [Album]s, null if empty. * @param artists A list of [Artist]s, null if empty. @@ -66,11 +69,12 @@ class SearchEngineImpl @Inject constructor(@ApplicationContext private val conte /** * Search a given [Music] list. + * * @param query The query to search for. The routine will compare this query to the names of - * each object in the list and + * each object in the list and * @param fallback Additional comparison code to run if the item does not match the query - * initially. This can be used to compare against additional attributes to improve search result - * quality. + * initially. This can be used to compare against additional attributes to improve search + * result quality. */ private inline fun List.searchListImpl( query: String, diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index caf9c57ad..ccf5f4e30 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -49,11 +49,10 @@ import org.oxycblt.auxio.util.* /** * The [ListFragment] providing search functionality for the music library. * - * TODO: Better keyboard management - * - * TODO: Multi-filtering with chips - * * @author Alexander Capehart (OxygenCobalt) + * + * TODO: Better keyboard management + * TODO: Multi-filtering with chips */ @AndroidEntryPoint class SearchFragment : ListFragment() { @@ -201,6 +200,7 @@ class SearchFragment : ListFragment() { /** * Safely focus the keyboard on a particular [View]. + * * @param view The [View] to focus the keyboard on. */ private fun showKeyboard(view: View) { diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt index edd22439f..fe7a9a6e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.settings.Settings /** * User configuration specific to the search UI. + * * @author Alexander Capehart (OxygenCobalt) */ interface SearchSettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt index 6fdf615fd..17e6675f1 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt @@ -38,6 +38,7 @@ import org.oxycblt.auxio.util.logD /** * An [ViewModel] that keeps performs search operations and tracks their results. + * * @author Alexander Capehart (OxygenCobalt) */ @HiltViewModel @@ -80,6 +81,7 @@ constructor( /** * Asynchronously search the music library. Results will be pushed to [searchResults]. Will * cancel any previous search operations started prior. + * * @param query The query to search the music library for. */ fun search(query: String?) { @@ -142,6 +144,7 @@ constructor( /** * Returns the ID of the filter option to currently highlight. + * * @return A menu item ID of the filtering option selected. */ @IdRes @@ -157,6 +160,7 @@ constructor( /** * Update the filter mode with the newly-selected filter option. + * * @return A menu item ID of the new filtering option selected. */ fun setFilterOptionId(@IdRes id: Int) { diff --git a/app/src/main/java/org/oxycblt/auxio/service/ForegroundManager.kt b/app/src/main/java/org/oxycblt/auxio/service/ForegroundManager.kt index cebb96001..ce355abc7 100644 --- a/app/src/main/java/org/oxycblt/auxio/service/ForegroundManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/service/ForegroundManager.kt @@ -23,6 +23,7 @@ import org.oxycblt.auxio.util.logD /** * A utility to create consistent foreground behavior for a given [Service]. + * * @param service [Service] to wrap in this instance. * @author Alexander Capehart (OxygenCobalt) * @@ -38,8 +39,9 @@ class ForegroundManager(private val service: Service) { /** * Try to enter a foreground state. + * * @param notification The [ForegroundServiceNotification] to show in order to signal the - * foreground state. + * foreground state. * @return true if the state was changed, false otherwise * @see Service.startForeground */ @@ -57,6 +59,7 @@ class ForegroundManager(private val service: Service) { /** * Try to exit a foreground state. Will remove the foreground notification. + * * @return true if the state was changed, false otherwise * @see Service.stopForeground */ diff --git a/app/src/main/java/org/oxycblt/auxio/service/ForegroundServiceNotification.kt b/app/src/main/java/org/oxycblt/auxio/service/ForegroundServiceNotification.kt index c42d126a6..6185a8ab8 100644 --- a/app/src/main/java/org/oxycblt/auxio/service/ForegroundServiceNotification.kt +++ b/app/src/main/java/org/oxycblt/auxio/service/ForegroundServiceNotification.kt @@ -26,6 +26,7 @@ import androidx.core.app.NotificationManagerCompat /** * Wrapper around [NotificationCompat.Builder] intended for use for [NotificationCompat]s that * signal a Service's ongoing foreground state. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class ForegroundServiceNotification(context: Context, info: ChannelInfo) : @@ -47,6 +48,7 @@ abstract class ForegroundServiceNotification(context: Context, info: ChannelInfo /** * The code used to identify this notification. + * * @see NotificationManagerCompat.notify */ abstract val code: Int @@ -60,6 +62,7 @@ abstract class ForegroundServiceNotification(context: Context, info: ChannelInfo /** * Reduced representation of a [NotificationChannelCompat]. + * * @param id The ID of the channel. * @param nameRes A string resource ID corresponding to the human-readable name of this channel. */ 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 c5a01cfb5..d78227ad7 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt @@ -42,6 +42,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [ViewBindingFragment] that displays information about the app and the current music library. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint @@ -93,6 +94,7 @@ class AboutFragment : ViewBindingFragment() { /** * Open the given URI in a web browser. + * * @param uri The URL to open. */ private fun openLinkInBrowser(uri: String) { @@ -143,6 +145,7 @@ class AboutFragment : ViewBindingFragment() { /** * Open an app chooser for a given [Intent]. + * * @param intent The [Intent] to show an app chooser for. */ private fun openAppChooser(intent: Intent) { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/BasePreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/BasePreferenceFragment.kt index 547c245e3..d1cf0b8fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/BasePreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/BasePreferenceFragment.kt @@ -41,18 +41,21 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat /** * Shared [PreferenceFragmentCompat] used across all preference screens. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class BasePreferenceFragment(@XmlRes private val screen: Int) : PreferenceFragmentCompat() { /** * Called when the UI entry of a given [Preference] needs to be configured. + * * @param preference The [Preference] to configure. */ open fun onSetupPreference(preference: Preference) {} /** * Called when an arbitrary [WrappedDialogPreference] needs to be opened. + * * @param preference The [WrappedDialogPreference] to open. */ open fun onOpenDialogPreference(preference: WrappedDialogPreference) {} diff --git a/app/src/main/java/org/oxycblt/auxio/settings/RootPreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/RootPreferenceFragment.kt index bc4622dc1..5aaa73fee 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/RootPreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/RootPreferenceFragment.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.util.showToast /** * The [PreferenceFragmentCompat] that displays the root settings list. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint 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 5bc4448b9..c43667c60 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -27,11 +27,13 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * Abstract user configuration information. This interface has no functionality whatsoever. Concrete * implementations should be preferred instead. + * * @author Alexander Capehart (OxygenCobalt) */ interface Settings { /** * Migrate any settings fields from older versions into their new counterparts. + * * @throws NotImplementedError If there is nothing to migrate. */ fun migrate() { @@ -40,18 +42,21 @@ interface Settings { /** * Add a listener to monitor for settings updates. Will do nothing if + * * @param listener The listener to add. */ fun registerListener(listener: L) /** * Unregister a listener, preventing any further settings updates from being sent to it. + * * @param listener The listener to unregister, must be the same as the current listener. */ fun unregisterListener(listener: L) /** * A framework-backed [Settings] implementation. + * * @param context [Context] required. */ abstract class Impl(private val context: Context) : @@ -91,6 +96,7 @@ interface Settings { /** * Called when a setting entry with the given [key] has changed. + * * @param key The key of the changed setting. * @param listener The implementation's listener that updates should be applied to. */ diff --git a/app/src/main/java/org/oxycblt/auxio/settings/categories/AudioPreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/categories/AudioPreferenceFragment.kt index 52506caf5..292c44930 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/categories/AudioPreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/categories/AudioPreferenceFragment.kt @@ -24,6 +24,7 @@ import org.oxycblt.auxio.settings.ui.WrappedDialogPreference /** * Audio settings interface. + * * @author Alexander Capehart (OxygenCobalt) */ class AudioPreferenceFragment : BasePreferenceFragment(R.xml.preferences_audio) { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt index 1ee5e05e6..ae095e64f 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.settings.ui.WrappedDialogPreference /** * "Content" settings. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/settings/categories/PersonalizePreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/categories/PersonalizePreferenceFragment.kt index 73c5147ec..f33a86231 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/categories/PersonalizePreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/categories/PersonalizePreferenceFragment.kt @@ -24,6 +24,7 @@ import org.oxycblt.auxio.settings.ui.WrappedDialogPreference /** * Personalization settings interface. + * * @author Alexander Capehart (OxygenCobalt) */ class PersonalizePreferenceFragment : BasePreferenceFragment(R.xml.preferences_personalize) { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/categories/UIPreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/categories/UIPreferenceFragment.kt index 4e564e9d5..94abb8e21 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/categories/UIPreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/categories/UIPreferenceFragment.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.isNight /** * Display preferences. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt index 1289e121e..8cfa3e4bd 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt @@ -114,8 +114,9 @@ constructor( /** * Get the index of the current value. + * * @return The index of the current value within [values], or -1 if the [IntListPreference] is - * not set. + * not set. */ fun getValueIndex(): Int { val curValue = currentValue @@ -127,6 +128,7 @@ constructor( /** * Set the current value of this preference using it's index. + * * @param index The index of the new value within [values]. Must be valid. */ fun setValueIndex(index: Int) { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreferenceDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreferenceDialog.kt index 5613e1ef3..35a2446e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreferenceDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreferenceDialog.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.util.fixDoubleRipple /** * The companion dialog to [IntListPreference]. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class IntListPreferenceDialog : PreferenceDialogFragmentCompat() { @@ -72,6 +73,7 @@ class IntListPreferenceDialog : PreferenceDialogFragmentCompat() { /** * Create a new instance. + * * @param preference The [IntListPreference] to display. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/PreferenceHeaderItemDecoration.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/PreferenceHeaderItemDecoration.kt index 5ab4b0ebf..c62ebfde4 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/ui/PreferenceHeaderItemDecoration.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/PreferenceHeaderItemDecoration.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.R /** * A [BackportMaterialDividerItemDecoration] that sets up the divider configuration to correctly * separate preference categories. + * * @author Alexander Capehart (OxygenCobalt) */ class PreferenceHeaderItemDecoration diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt index ec5317b4e..d13c5c735 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt @@ -24,6 +24,7 @@ import androidx.preference.DialogPreference /** * Wraps a [DialogPreference] to be instantiatable. This has no purpose other to ensure that custom * dialog preferences are handled. + * * @author Alexander Capehart (OxygenCobalt) */ class WrappedDialogPreference diff --git a/app/src/main/java/org/oxycblt/auxio/ui/BaseBottomSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/ui/BaseBottomSheetBehavior.kt index aefcedd1e..dbb5091cc 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/BaseBottomSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/BaseBottomSheetBehavior.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.util.systemGestureInsetsCompat * 1. No reasonable edge-to-edge support. * 2. Strange corner radius behaviors. * 3. Inability to skip half-expanded state when full-screen. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class BaseBottomSheetBehavior(context: Context, attributeSet: AttributeSet?) : @@ -48,6 +49,7 @@ abstract class BaseBottomSheetBehavior(context: Context, attributeSet: /** * Create a background [Drawable] to use for this [BaseBottomSheetBehavior]'s child [View]. + * * @param context [Context] that can be used to draw the [Drawable]. * @return A background drawable. */ @@ -56,6 +58,7 @@ abstract class BaseBottomSheetBehavior(context: Context, attributeSet: /** * Called when window insets are being applied to the [View] this [BaseBottomSheetBehavior] is * linked to. + * * @param child The child view receiving the [WindowInsets]. * @param insets The [WindowInsets] to apply. * @return The (possibly modified) [WindowInsets]. diff --git a/app/src/main/java/org/oxycblt/auxio/ui/BottomSheetContentBehavior.kt b/app/src/main/java/org/oxycblt/auxio/ui/BottomSheetContentBehavior.kt index 77f1cfc01..bbc8bf8ab 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/BottomSheetContentBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/BottomSheetContentBehavior.kt @@ -32,6 +32,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat * A behavior that automatically re-layouts and re-insets content to align with the parent layout's * bottom sheet. Ideally, we would only want to re-inset content, but that has too many issues to * sensibly implement. + * * @author Alexander Capehart (OxygenCobalt) */ class BottomSheetContentBehavior(context: Context, attributeSet: AttributeSet?) : diff --git a/app/src/main/java/org/oxycblt/auxio/ui/CoordinatorAppBarLayout.kt b/app/src/main/java/org/oxycblt/auxio/ui/CoordinatorAppBarLayout.kt index 3a14709b5..6bc72f509 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/CoordinatorAppBarLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/CoordinatorAppBarLayout.kt @@ -110,6 +110,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr * An [AppBarLayout.OnOffsetChangedListener] that will automatically move the given * [RecyclerView] as the [AppBarLayout] expands. Should be added right when the view is * expanding. Will be removed automatically. + * * @param recycler [RecyclerView] to scroll with the [AppBarLayout]. */ private class ExpansionHackListener(private val recycler: RecyclerView) : diff --git a/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt b/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt index becc077ad..d6b9fb608 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/NavigationViewModel.kt @@ -57,6 +57,7 @@ class NavigationViewModel : ViewModel() { * Navigate to something in the main navigation graph. This can be used by UIs in the explore * navigation graph to trigger navigation in the higher-level main navigation graph. Will do * nothing if already navigating. + * * @param action The [MainNavigationAction] to perform. */ fun mainNavigateTo(action: MainNavigationAction) { @@ -79,6 +80,7 @@ class NavigationViewModel : ViewModel() { /** * Navigate to a given [Music] item. Will do nothing if already navigating. + * * @param music The [Music] to navigate to. */ fun exploreNavigateTo(music: Music) { @@ -92,8 +94,9 @@ class NavigationViewModel : ViewModel() { /** * Navigate to one of the parent [Artist]'s of the given [Song]. + * * @param song The [Song] to navigate with. If there are multiple parent [Artist]s, a picker - * dialog will be shown. + * dialog will be shown. */ fun exploreNavigateToParentArtist(song: Song) { exploreNavigateToParentArtistImpl(song, song.artists) @@ -101,8 +104,9 @@ class NavigationViewModel : ViewModel() { /** * Navigate to one of the parent [Artist]'s of the given [Album]. + * * @param album The [Album] to navigate with. If there are multiple parent [Artist]s, a picker - * dialog will be shown. + * dialog will be shown. */ fun exploreNavigateToParentArtist(album: Album) { exploreNavigateToParentArtistImpl(album, album.artists) @@ -137,6 +141,7 @@ class NavigationViewModel : ViewModel() { * Represents the possible actions within the main navigation graph. This can be used with * [NavigationViewModel] to initiate navigation in the main navigation graph from anywhere in the * app, including outside the main navigation graph. + * * @author Alexander Capehart (OxygenCobalt) */ sealed class MainNavigationAction { @@ -148,8 +153,9 @@ sealed class MainNavigationAction { /** * Navigate to the given [NavDirections]. + * * @param directions The [NavDirections] to navigate to. Assumed to be part of the main - * navigation graph. + * navigation graph. */ data class Directions(val directions: NavDirections) : MainNavigationAction() } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/RippleFixMaterialButton.kt b/app/src/main/java/org/oxycblt/auxio/ui/RippleFixMaterialButton.kt index 514858f63..0d3b9d43e 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/RippleFixMaterialButton.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/RippleFixMaterialButton.kt @@ -27,6 +27,7 @@ import org.oxycblt.auxio.util.fixDoubleRipple /** * Fixes an issue where double ripples appear on [MaterialButton] from AppCompat 1.5 afterwards due * to a currently unfixed change. + * * @author Alexander Capehart (OxygenCobalt) */ open class RippleFixMaterialButton diff --git a/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt b/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt index 10f8bbc52..c848acd78 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.logD /** * User configuration for the general app UI. + * * @author Alexander Capehart (OxygenCobalt) */ interface UISettings : Settings { diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt index 1b9a5eb47..47c3a27d0 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingDialogFragment.kt @@ -32,6 +32,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A lifecycle-aware [DialogFragment] that automatically manages the [ViewBinding] lifecycle. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class ViewBindingDialogFragment : DialogFragment() { @@ -39,6 +40,7 @@ abstract class ViewBindingDialogFragment : DialogFragment() { /** * Configure the [AlertDialog.Builder] during [onCreateDialog]. + * * @param builder The [AlertDialog.Builder] to configure. * @see onCreateDialog */ @@ -46,6 +48,7 @@ abstract class ViewBindingDialogFragment : DialogFragment() { /** * Inflate the [ViewBinding] during [onCreateView]. + * * @param inflater The [LayoutInflater] to inflate the [ViewBinding] with. * @return A new [ViewBinding] instance. * @see onCreateView @@ -54,6 +57,7 @@ abstract class ViewBindingDialogFragment : DialogFragment() { /** * Configure the newly-inflated [ViewBinding] during [onViewCreated]. + * * @param binding The [ViewBinding] to configure. * @param savedInstanceState The previously saved state of the UI. * @see onViewCreated @@ -62,6 +66,7 @@ abstract class ViewBindingDialogFragment : DialogFragment() { /** * Free memory held by the [ViewBinding] during [onDestroyView] + * * @param binding The [ViewBinding] to release. * @see onDestroyView */ @@ -73,6 +78,7 @@ abstract class ViewBindingDialogFragment : DialogFragment() { /** * Get the [ViewBinding] under the assumption that it has been inflated. + * * @return The currently-inflated [ViewBinding]. * @throws IllegalStateException if the [ViewBinding] is not inflated. */ diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt index aaaf3119e..faff8cce1 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ViewBindingFragment.kt @@ -28,6 +28,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A fragment enabling ViewBinding inflation and usage across the fragment lifecycle. + * * @author Alexander Capehart (OxygenCobalt) */ abstract class ViewBindingFragment : Fragment() { @@ -35,6 +36,7 @@ abstract class ViewBindingFragment : Fragment() { /** * Inflate the [ViewBinding] during [onCreateView]. + * * @param inflater The [LayoutInflater] to inflate the [ViewBinding] with. * @return A new [ViewBinding] instance. * @see onCreateView @@ -43,6 +45,7 @@ abstract class ViewBindingFragment : Fragment() { /** * Configure the newly-inflated [ViewBinding] during [onViewCreated]. + * * @param binding The [ViewBinding] to configure. * @param savedInstanceState The previously saved state of the UI. * @see onViewCreated @@ -51,6 +54,7 @@ abstract class ViewBindingFragment : Fragment() { /** * Free memory held by the [ViewBinding] during [onDestroyView] + * * @param binding The [ViewBinding] to release. * @see onDestroyView */ @@ -62,6 +66,7 @@ abstract class ViewBindingFragment : Fragment() { /** * Get the [ViewBinding] under the assumption that it has been inflated. + * * @return The currently-inflated [ViewBinding]. * @throws IllegalStateException if the [ViewBinding] is not inflated. */ diff --git a/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt index cfa6525bd..a128eeea8 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/Accent.kt @@ -134,9 +134,10 @@ class Accent private constructor(val index: Int) { companion object { /** * Create a new instance. + * * @param index The unique number for this particular accent. * @return A new [Accent] with the specified [index]. If [index] is not within the range of - * valid accents, [index] will be [DEFAULT] instead. + * valid accents, [index] will be [DEFAULT] instead. */ fun from(index: Int): Accent { if (index !in 0 until MAX) { diff --git a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt index 46e7e66fc..eea6ee79a 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentAdapter.kt @@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.inflater /** * A [RecyclerView.Adapter] that displays [Accent] choices. + * * @param listener A [ClickableListListener] to bind interactions to. * @author Alexander Capehart (OxygenCobalt) */ @@ -62,6 +63,7 @@ class AccentAdapter(private val listener: ClickableListListener) : /** * Update the currently selected [Accent]. + * * @param accent The new [Accent] to select. */ fun setSelectedAccent(accent: Accent) { @@ -83,6 +85,7 @@ class AccentAdapter(private val listener: ClickableListListener) : /** * A [RecyclerView.ViewHolder] that displays an [Accent] choice. Use [from] to create an instance. + * * @author Alexander Capehart (OxygenCobalt) */ class AccentViewHolder private constructor(private val binding: ItemAccentBinding) : @@ -90,6 +93,7 @@ class AccentViewHolder private constructor(private val binding: ItemAccentBindin /** * Bind new data to this instance. + * * @param accent The new [Accent] to bind. * @param listener A [ClickableListListener] to bind interactions to. */ @@ -106,6 +110,7 @@ class AccentViewHolder private constructor(private val binding: ItemAccentBindin /** * Set whether this [Accent] is selected or not. + * * @param isSelected Whether this [Accent] is currently selected. */ fun setSelected(isSelected: Boolean) { @@ -122,6 +127,7 @@ class AccentViewHolder private constructor(private val binding: ItemAccentBindin companion object { /** * Create a new instance. + * * @param parent The parent to inflate this instance from. * @return A new instance. */ diff --git a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt index 1c9a042f5..18c925f80 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull /** * A [ViewBindingDialogFragment] that allows the user to configure the current [Accent]. + * * @author Alexander Capehart (OxygenCobalt) */ @AndroidEntryPoint diff --git a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt index 85aa256da..2238ccf65 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt @@ -43,6 +43,7 @@ import org.oxycblt.auxio.R /** * Get a [LayoutInflater] instance from this [Context]. + * * @see LayoutInflater.from */ val Context.inflater: LayoutInflater @@ -60,6 +61,7 @@ val Context.isLandscape /** * Concatenate values in a list together in a localized manner. + * * @param context [Context] require.d * @param map Function to map the [T] values to a string value to be concatenated. */ @@ -78,23 +80,24 @@ inline fun List.concatLocalized(context: Context, map: (T) -> String): St } /** - * @brief Get a plural resource. * @param pluralRes A plural resource ID. * @param value Int value for the plural. * @return The formatted string requested. + * @brief Get a plural resource. */ fun Context.getPlural(@PluralsRes pluralRes: Int, value: Int) = resources.getQuantityString(pluralRes, value, value) /** - * @brief Get an integer resource. * @param integerRes An integer resource ID. * @return The integer resource requested. + * @brief Get an integer resource. */ fun Context.getInteger(@IntegerRes integerRes: Int) = resources.getInteger(integerRes) /** * Get a [ColorStateList] resource. + * * @param colorRes A color resource ID. * @return The [ColorStateList] requested. */ @@ -105,6 +108,7 @@ fun Context.getColorCompat(@ColorRes colorRes: Int) = /** * Get a [ColorStateList] pointed to by an attribute. + * * @param attrRes An attribute resource ID. * @return The [ColorStateList] the requested attribute points to. */ @@ -126,6 +130,7 @@ fun Context.getAttrColorCompat(@AttrRes attrRes: Int): ColorStateList { /** * Get a Drawable. + * * @param drawableRes The Drawable resource ID. * @return The Drawable requested. */ @@ -136,6 +141,7 @@ fun Context.getDrawableCompat(@DrawableRes drawableRes: Int) = /** * Get the complex (i.e DP) size of a dimension. + * * @param dimenRes The dimension resource. * @return The size of the dimension requested, in complex units. */ @@ -143,6 +149,7 @@ fun Context.getDrawableCompat(@DrawableRes drawableRes: Int) = /** * Get the pixel size of a dimension. + * * @param dimenRes The dimension resource * @return The size of the dimension requested, in pixels */ @@ -150,6 +157,7 @@ fun Context.getDrawableCompat(@DrawableRes drawableRes: Int) = /** * Get an instance of the requested system service. + * * @param T The system service in question. * @param serviceClass The service's kotlin class [Java class will be used in function call] * @return The system service @@ -162,6 +170,7 @@ fun Context.getSystemServiceCompat(serviceClass: KClass) = /** * Create a short-length [Toast] with text from the specified string resource. + * * @param stringRes The resource to the string to use in the toast. */ fun Context.showToast(@StringRes stringRes: Int) { @@ -178,6 +187,7 @@ fun Context.newMainPendingIntent(): PendingIntent = /** * Create a [PendingIntent] that will broadcast the specified command when launched. + * * @param action The action to broadcast when the [PendingIntent] is launched. */ fun Context.newBroadcastPendingIntent(action: String): PendingIntent = diff --git a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt index e81dc11d3..e66a52207 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt @@ -41,12 +41,13 @@ import kotlinx.coroutines.launch /** * Get if this [View] contains the given [PointF], with optional leeway. + * * @param x The x value of the point to check. * @param y The y value of the point to check. * @param minTouchTargetSize A minimum size to use when checking the value. This can be used to - * extend the range where a point is considered "contained" by the [View] beyond it's actual size. + * extend the range where a point is considered "contained" by the [View] beyond it's actual size. * @return true if the [PointF] is contained by the view, false otherwise. Adapted from - * AndroidFastScroll: https://github.com/zhanghai/AndroidFastScroll + * AndroidFastScroll: https://github.com/zhanghai/AndroidFastScroll */ fun View.isUnder(x: Float, y: Float, minTouchTargetSize: Int = 0) = isUnderImpl(x, left, right, (parent as View).width, minTouchTargetSize) && @@ -54,6 +55,7 @@ fun View.isUnder(x: Float, y: Float, minTouchTargetSize: Int = 0) = /** * Internal implementation of [isUnder]. + * * @param position The position to check. * @param viewStart The start of the view bounds, on the same axis as [position]. * @param viewEnd The end of the view bounds, on the same axis as [position] @@ -129,6 +131,7 @@ val View.coordinatorLayoutBehavior: CoordinatorLayout.Behavior? * Collect a [StateFlow] into [block] in a lifecycle-aware manner *eventually.* Due to co-routine * launching, the initializing call will occur ~100ms after draw time. If this is not desirable, use * [collectImmediately]. + * * @param stateFlow The [StateFlow] to collect. * @param block The code to run when the [StateFlow] updates. */ @@ -140,6 +143,7 @@ fun Fragment.collect(stateFlow: StateFlow, block: (T) -> Unit) { * Collect a [StateFlow] into a [block] in a lifecycle-aware manner *immediately.* This will * immediately run an initializing call to ensure the UI is set up before draw-time. Note that this * will result in two initializing calls. + * * @param stateFlow The [StateFlow] to collect. * @param block The code to run when the [StateFlow] updates. */ @@ -151,6 +155,7 @@ fun Fragment.collectImmediately(stateFlow: StateFlow, block: (T) -> Unit) /** * Like [collectImmediately], but with two [StateFlow] instances that are collected with the same * block. + * * @param a The first [StateFlow] to collect. * @param b The second [StateFlow] to collect. * @param block The code to run when either [StateFlow] updates. @@ -171,6 +176,7 @@ fun Fragment.collectImmediately( /** * Like [collectImmediately], but with three [StateFlow] instances that are collected with the same * block. + * * @param a The first [StateFlow] to collect. * @param b The second [StateFlow] to collect. * @param c The third [StateFlow] to collect. @@ -191,6 +197,7 @@ fun Fragment.collectImmediately( * Launch a [Fragment] co-routine whenever the [Lifecycle] hits the given [Lifecycle.State]. This * should always been used when launching [Fragment] co-routines was it will not result in * unexpected behavior. + * * @param state The [Lifecycle.State] to launch the co-routine in. * @param block The block to run in the co-routine. * @see repeatOnLifecycle @@ -250,6 +257,7 @@ val WindowInsets.systemGestureInsetsCompat: Insets /** * Returns the given [Insets] based on the to the API 30+ [WindowInsets] convention. + * * @param typeMask The type of [Insets] to obtain. * @return Compat [Insets] corresponding to the given type. * @see WindowInsets.getInsets @@ -259,6 +267,7 @@ private fun WindowInsets.getCompatInsets(typeMask: Int) = Insets.toCompatInsets( /** * Returns "System Bar" [Insets] based on the API 21+ [WindowInsets] convention. + * * @return Compat [Insets] consisting of the [WindowInsets] "System Bar" [Insets] field. * @see WindowInsets.getSystemWindowInsets */ @@ -272,6 +281,7 @@ private fun WindowInsets.getSystemWindowCompatInsets() = /** * Returns "System Bar" [Insets] based on the API 29 [WindowInsets] convention. + * * @return Compat [Insets] consisting of the [WindowInsets] "System Gesture" [Insets] fields. * @see WindowInsets.getSystemGestureInsets */ @@ -281,6 +291,7 @@ private fun WindowInsets.getSystemGestureCompatInsets() = Insets.toCompatInsets( /** * Replace the "System Bar" [Insets] in [WindowInsets] with a new set of [Insets]. + * * @param left The new left inset. * @param top The new top inset. * @param right The new right inset. diff --git a/app/src/main/java/org/oxycblt/auxio/util/LangUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/LangUtil.kt index 71b963b38..dd47f9418 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/LangUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/LangUtil.kt @@ -35,6 +35,7 @@ fun unlikelyToBeNull(value: T?) = /** * Require that the given data is a specific type [T]. + * * @param data The data to check. * @return A data casted to [T]. * @throws IllegalStateException If the data cannot be casted to [T]. @@ -46,18 +47,21 @@ inline fun requireIs(data: Any?): T { /** * Aliases a check to ensure that the given number is non-zero. + * * @return The given number if it's non-zero, null otherwise. */ fun Int.nonZeroOrNull() = if (this > 0) this else null /** * Aliases a check to ensure that the given number is non-zero. + * * @return The same number if it's non-zero, null otherwise. */ fun Long.nonZeroOrNull() = if (this > 0) this else null /** * Aliases a check to ensure a given value is in a specified range. + * * @param range The valid range of values for this number. * @return The same number if it is in the range, null otherwise. */ @@ -66,6 +70,7 @@ fun Int.inRangeOrNull(range: IntRange) = if (range.contains(this)) this else nul /** * Lazily set up a reflected field. Automatically handles visibility changes. Adapted from Material * Files: https://github.com/zhanghai/MaterialFiles + * * @param clazz The [KClass] to reflect into. * @param field The name of the field to obtain. */ @@ -75,6 +80,7 @@ fun lazyReflectedField(clazz: KClass<*>, field: String) = lazy { /** * Lazily set up a reflected method. Automatically handles visibility changes. Adapted from Material * Files: https://github.com/zhanghai/MaterialFiles + * * @param clazz The [KClass] to reflect into. * @param method The name of the method to obtain. */ @@ -84,6 +90,7 @@ fun lazyReflectedMethod(clazz: KClass<*>, method: String) = lazy { /** * Convert a [String] to a [UUID]. + * * @return A [UUID] converted from the [String] value, or null if the value was not valid. * @see UUID.fromString */ 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 ee447580d..e2b766a8e 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/LogUtil.kt @@ -25,12 +25,14 @@ import org.oxycblt.auxio.BuildConfig /** * Log an object to the debug channel. Automatically handles tags. + * * @param obj The object to log. */ fun Any.logD(obj: Any?) = logD("$obj") /** * Log a string message to the debug channel. Automatically handles tags. + * * @param msg The message to log. */ fun Any.logD(msg: String) { @@ -41,12 +43,14 @@ fun Any.logD(msg: String) { /** * Log a string message to the warning channel. Automatically handles tags. + * * @param msg The message to log. */ fun Any.logW(msg: String) = Log.w(autoTag, msg) /** * Log a string message to the error channel. Automatically handles tags. + * * @param msg The message to log. */ fun Any.logE(msg: String) = Log.e(autoTag, msg) diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index ebea97289..9c1e9eab6 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -41,6 +41,7 @@ import org.oxycblt.auxio.util.logD /** * A component that manages the "Now Playing" state. This is kept separate from the [WidgetProvider] * itself to prevent possible memory leaks and enable extension to more widgets in the future. + * * @author Alexander Capehart (OxygenCobalt) */ class WidgetComponent @@ -134,6 +135,7 @@ constructor( /** * A condensed form of the playback state that is safe to use in AppWidgets. + * * @param song [Queue.currentSong] * @param cover A pre-loaded album cover [Bitmap] for [song]. * @param isPlaying [PlaybackStateManager.playerState] diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt index ca737e8ef..171ad805b 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt @@ -38,6 +38,7 @@ import org.oxycblt.auxio.util.* /** * The [AppWidgetProvider] for the "Now Playing" widget. This widget shows the current playback * state alongside actions to control it. + * * @author Alexander Capehart (OxygenCobalt) */ class WidgetProvider : AppWidgetProvider() { @@ -69,6 +70,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Update the currently shown layout based on the given [WidgetComponent.PlaybackState] + * * @param context [Context] required to update the widget layout. * @param uiSettings [UISettings] to obtain round mode configuration * @param state [WidgetComponent.PlaybackState] to show, or null if no playback is going on. @@ -105,6 +107,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Revert to the default layout that displays "No music playing". + * * @param context [Context] required to update the widget layout. */ fun reset(context: Context) { @@ -117,6 +120,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Request an update from [WidgetComponent]. + * * @param context [Context] required to send update request broadcast. */ private fun requestUpdate(context: Context) { @@ -231,6 +235,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Set up the album cover in a [RemoteViews] layout that contains one. + * * @param context [Context] required to set up the view. * @param state Current [WidgetComponent.PlaybackState] to display. */ @@ -257,6 +262,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Set up the album cover, song title, and artist name in a [RemoteViews] layout that contains * them. + * * @param context [Context] required to set up the view. * @param state Current [WidgetComponent.PlaybackState] to display. */ @@ -272,6 +278,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Set up the play/pause button in a [RemoteViews] layout that contains one. + * * @param context [Context] required to set up the view. * @param state Current [WidgetComponent.PlaybackState] to display. */ @@ -308,6 +315,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Set up the play/pause and skip previous/next button in a [RemoteViews] layout that contains * them. + * * @param context [Context] required to set up the view. * @param state Current [WidgetComponent.PlaybackState] to display. */ @@ -333,6 +341,7 @@ class WidgetProvider : AppWidgetProvider() { /** * Set up the play/pause, skip previous/next, and repeat/shuffle buttons in a [RemoteViews] that * contains them. + * * @param context [Context] required to set up the view. * @param state Current [WidgetComponent.PlaybackState] to display. */ diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt index 3a478b6ff..567ed6751 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.util.newMainPendingIntent /** * Create a [RemoteViews] instance with the specified layout and an automatic click handler to open * the Auxio activity. + * * @param context [Context] required to create [RemoteViews]. * @param layoutRes Resource ID of the layout to use. Must be compatible with [RemoteViews]. * @return A new [RemoteViews] instance with the specified configuration. @@ -48,9 +49,10 @@ fun newRemoteViews(context: Context, @LayoutRes layoutRes: Int): RemoteViews { /** * Get an image size guaranteed to not exceed the [RemoteViews] bitmap memory limit, assuming that * there is only one image. + * * @param context [Context] required to perform calculation. * @param reduce Optional multiplier to reduce the image size. Recommended value is 2 to avoid - * device-specific variations in memory limit. + * device-specific variations in memory limit. * @return The dimension of a bitmap that can be safely used in [RemoteViews]. */ fun getSafeRemoteViewsImageSize(context: Context, reduce: Float = 2f): Int { @@ -64,6 +66,7 @@ fun getSafeRemoteViewsImageSize(context: Context, reduce: Float = 2f): Int { /** * Set the background resource of a [RemoteViews] View. + * * @param viewId The ID of the view to update. * @param drawableRes The resource ID of the drawable to set the background to. */ @@ -73,6 +76,7 @@ fun RemoteViews.setBackgroundResource(@IdRes viewId: Int, @DrawableRes drawableR /** * Set the layout direction of a [RemoteViews] view. + * * @param viewId The ID of the view to update. * @param layoutDirection The layout direction to apply to the view, */ @@ -83,6 +87,7 @@ fun RemoteViews.setLayoutDirection(@IdRes viewId: Int, layoutDirection: Int) { /** * Update the app widget layouts corresponding to the given [WidgetProvider] [ComponentName] with an * adaptive layout, in a version-compatible manner. + * * @param context [Context] required to backport adaptive layout behavior. * @param component [ComponentName] of the app widget layout to update. * @param views Mapping between different size classes and [RemoteViews] instances. @@ -137,6 +142,7 @@ fun AppWidgetManager.updateAppWidgetCompat( /** * Returns whether rounded UI elements are appropriate for the widget, either based on the current * settings or if the widget has to fit in aesthetically with other widgets. + * * @param [uiSettings] [UISettings] required to obtain round mode configuration. * @return true if to use round mode, false otherwise. */ diff --git a/build.gradle b/build.gradle index b47468ebe..1cdbe5559 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ buildscript { classpath 'com.android.tools.build:gradle:7.4.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version" - classpath "com.diffplug.spotless:spotless-plugin-gradle:6.10.0" + classpath "com.diffplug.spotless:spotless-plugin-gradle:6.15.0" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle.properties b/gradle.properties index 9bb1cb21f..f6e147bcb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,6 +16,6 @@ org.gradle.jvmargs=-Xmx2048m # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true +android.enableJetifier=false # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official