Make music models inherit base class

Make the music models inherit a base data class that contains the ID & name to reduce redundant code.
This commit is contained in:
OxygenCobalt 2020-09-27 10:26:14 -06:00
parent 9ffc194c4d
commit d99347722e
33 changed files with 144 additions and 178 deletions

View file

@ -13,8 +13,8 @@ import androidx.navigation.fragment.navArgs
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.applyDivider

View file

@ -3,9 +3,9 @@ package org.oxycblt.auxio.detail
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.recycler.SortMode
class DetailViewModel : ViewModel() {

View file

@ -11,13 +11,10 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.applyDivider

View file

@ -5,13 +5,13 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.recycler.AlbumDiffCallback
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.DiffCallback
class DetailAlbumAdapter(
private val listener: ClickListener<Album>
) : ListAdapter<Album, DetailAlbumAdapter.ViewHolder>(AlbumDiffCallback()) {
) : ListAdapter<Album, DetailAlbumAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(

View file

@ -4,17 +4,14 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.databinding.ItemGenreArtistBinding
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.recycler.AlbumDiffCallback
import org.oxycblt.auxio.recycler.ArtistDiffCallback
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.DiffCallback
class DetailArtistAdapter(
private val listener: ClickListener<Artist>
) : ListAdapter<Artist, DetailArtistAdapter.ViewHolder>(ArtistDiffCallback()) {
) : ListAdapter<Artist, DetailArtistAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(

View file

@ -5,13 +5,13 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SongDiffCallback
import org.oxycblt.auxio.recycler.DiffCallback
class DetailSongAdapter(
private val listener: ClickListener<Song>
) : ListAdapter<Song, DetailSongAdapter.ViewHolder>(SongDiffCallback()) {
) : ListAdapter<Song, DetailSongAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(

View file

@ -13,10 +13,10 @@ import org.oxycblt.auxio.databinding.FragmentLibraryBinding
import org.oxycblt.auxio.library.adapters.AlbumAdapter
import org.oxycblt.auxio.library.adapters.ArtistAdapter
import org.oxycblt.auxio.library.adapters.GenreAdapter
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.theme.SHOW_ALBUMS
import org.oxycblt.auxio.theme.SHOW_ARTISTS

View file

@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemAlbumBinding
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.recycler.ClickListener
class AlbumAdapter(

View file

@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemArtistBinding
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.recycler.ClickListener
class ArtistAdapter(

View file

@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemGenreBinding
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.recycler.ClickListener
class GenreAdapter(

View file

@ -0,0 +1,89 @@
package org.oxycblt.auxio.music
import android.net.Uri
// The base model for all music
// This is used in a lot of general functions in order to cut down on code
sealed class BaseModel {
abstract val id: Long
abstract val name: String
}
// Song
data class Song(
override val id: Long,
override var name: String,
val albumId: Long,
val track: Int,
val duration: Long
) : BaseModel() {
lateinit var album: Album
val seconds = duration / 1000
val formattedDuration: String = seconds.toDuration()
}
// Album
data class Album(
override val id: Long = -1,
override val name: String,
val artistName: String,
val coverUri: Uri = Uri.EMPTY,
val year: Int = 0
) : BaseModel() {
lateinit var artist: Artist
val songs = mutableListOf<Song>()
val numSongs: Int get() = songs.size
val totalDuration: String get() {
var seconds: Long = 0
songs.forEach {
seconds += it.seconds
}
return seconds.toDuration()
}
}
// Artist
data class Artist(
override val id: Long = -1,
override var name: String,
val givenGenres: MutableList<Genre> = mutableListOf()
) : BaseModel() {
val albums = mutableListOf<Album>()
val genres = mutableListOf<Genre>()
val numAlbums: Int get() = albums.size
val numSongs: Int
get() {
var num = 0
albums.forEach {
num += it.numSongs
}
return num
}
}
// Genre
data class Genre(
override val id: Long = -1,
override var name: String,
) : BaseModel() {
val artists = mutableListOf<Artist>()
val numArtists: Int get() = artists.size
val numAlbums: Int get() {
var num = 0
artists.forEach {
num += it.numAlbums
}
return num
}
val numSongs: Int get() {
var num = 0
artists.forEach {
num += it.numSongs
}
return num
}
}

View file

@ -8,9 +8,6 @@ import android.text.format.DateUtils
import android.widget.TextView
import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
// List of ID3 genres + Winamp extensions, each index corresponds to their int value.
// There are a lot more int-genre extensions as far as Im aware, but this works for most cases.

View file

@ -12,15 +12,11 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.processing.MusicLoader
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
import org.oxycblt.auxio.music.processing.MusicSorter
// ViewModel for music storage. May also be a god object.
// ViewModel for music storage.
// FIXME: This class can be improved in multiple ways
// - Remove lists/parents from models so that they can be parcelable
// - Move genre usage to songs [If there's a way to find songs without a genre]

View file

@ -7,10 +7,10 @@ import androidx.databinding.BindingAdapter
import coil.Coil
import coil.request.ImageRequest
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
// Get the cover art for a song or album
@BindingAdapter("coverArt")

View file

@ -5,7 +5,6 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.net.Uri
import android.util.Log
import androidx.core.graphics.drawable.toDrawable
import coil.bitmap.BitmapPool
import coil.decode.DataSource
@ -18,8 +17,6 @@ import coil.size.Size
import okio.buffer
import okio.source
import java.io.InputStream
import kotlin.math.pow
import kotlin.math.sqrt
const val MOSAIC_BITMAP_SIZE = 512
const val MOSAIC_BITMAP_INCREMENT = 256

View file

@ -1,25 +0,0 @@
package org.oxycblt.auxio.music.models
import android.net.Uri
import org.oxycblt.auxio.music.toDuration
// Abstraction for Song
data class Album(
val id: Long = -1,
var name: String,
val artistName: String,
val coverUri: Uri = Uri.EMPTY,
val year: Int = 0
) {
lateinit var artist: Artist
val songs = mutableListOf<Song>()
val numSongs: Int get() = songs.size
val totalDuration: String get() {
var seconds: Long = 0
songs.forEach {
seconds += it.seconds
}
return seconds.toDuration()
}
}

View file

@ -1,21 +0,0 @@
package org.oxycblt.auxio.music.models
// Abstraction for albums
data class Artist(
val id: Long = -1,
var name: String,
val givenGenres: MutableList<Genre> = mutableListOf()
) {
val albums = mutableListOf<Album>()
val genres = mutableListOf<Genre>()
val numAlbums: Int get() = albums.size
val numSongs: Int
get() {
var num = 0
albums.forEach {
num += it.numSongs
}
return num
}
}

View file

@ -1,24 +0,0 @@
package org.oxycblt.auxio.music.models
data class Genre(
val id: Long = -1,
var name: String,
) {
val artists = mutableListOf<Artist>()
val numArtists: Int get() = artists.size
val numAlbums: Int get() {
var num = 0
artists.forEach {
num += it.numAlbums
}
return num
}
val numSongs: Int get() {
var num = 0
artists.forEach {
num += it.numSongs
}
return num
}
}

View file

@ -1,17 +0,0 @@
package org.oxycblt.auxio.music.models
import org.oxycblt.auxio.music.toDuration
// Class containing all relevant values for a song.
data class Song(
val id: Long,
var name: String,
val albumId: Long,
val track: Int,
val duration: Long
) {
lateinit var album: Album
val seconds = duration / 1000
val formattedDuration: String = seconds.toDuration()
}

View file

@ -7,10 +7,10 @@ import android.provider.MediaStore.Audio.Artists
import android.provider.MediaStore.Audio.Genres
import android.provider.MediaStore.Audio.Media
import android.util.Log
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.toAlbumArtURI
import org.oxycblt.auxio.music.toNamedGenre

View file

@ -1,10 +1,10 @@
package org.oxycblt.auxio.music.processing
import android.util.Log
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
class MusicSorter(
var genres: MutableList<Genre>,

View file

@ -2,41 +2,21 @@ package org.oxycblt.auxio.recycler
import androidx.recyclerview.widget.DiffUtil
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Song
// RecyclerView click listener
class ClickListener<T>(val onClick: (T) -> Unit)
// Song Diff callback
class SongDiffCallback : DiffUtil.ItemCallback<Song>() {
override fun areContentsTheSame(oldItem: Song, newItem: Song): Boolean {
class DiffCallback<T : BaseModel> : DiffUtil.ItemCallback<T>() {
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem.id == newItem.id
}
override fun areItemsTheSame(oldItem: Song, newItem: Song): Boolean {
return oldItem == newItem
}
}
// Album Diff callback
class AlbumDiffCallback : DiffUtil.ItemCallback<Album>() {
override fun areContentsTheSame(oldItem: Album, newItem: Album): Boolean {
return oldItem.id == newItem.id
}
override fun areItemsTheSame(oldItem: Album, newItem: Album): Boolean {
return oldItem == newItem
}
}
class ArtistDiffCallback : DiffUtil.ItemCallback<Artist>() {
override fun areContentsTheSame(oldItem: Artist, newItem: Artist): Boolean {
return oldItem.id == newItem.id
}
override fun areItemsTheSame(oldItem: Artist, newItem: Artist): Boolean {
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem == newItem
}
}

View file

@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemSongBinding
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.recycler.ClickListener
class SongAdapter(

View file

@ -7,7 +7,7 @@
<variable
name="album"
type="org.oxycblt.auxio.music.models.Album" />
type="org.oxycblt.auxio.music.Album" />
<variable
name="detailModel"

View file

@ -7,7 +7,7 @@
<variable
name="artist"
type="org.oxycblt.auxio.music.models.Artist" />
type="org.oxycblt.auxio.music.Artist" />
<variable
name="detailModel"

View file

@ -6,7 +6,7 @@
<data>
<variable
name="genre"
type="org.oxycblt.auxio.music.models.Genre" />
type="org.oxycblt.auxio.music.Genre" />
<variable
name="detailModel"

View file

@ -7,7 +7,7 @@
<variable
name="album"
type="org.oxycblt.auxio.music.models.Album" />
type="org.oxycblt.auxio.music.Album" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout

View file

@ -7,7 +7,7 @@
<variable
name="song"
type="org.oxycblt.auxio.music.models.Song" />
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout

View file

@ -7,7 +7,7 @@
<variable
name="artist"
type="org.oxycblt.auxio.music.models.Artist" />
type="org.oxycblt.auxio.music.Artist" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout

View file

@ -7,7 +7,7 @@
<variable
name="album"
type="org.oxycblt.auxio.music.models.Album" />
type="org.oxycblt.auxio.music.Album" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@ -20,8 +20,8 @@
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/cover_size_large"
android:layout_height="@dimen/cover_size_large"
android:layout_width="@dimen/cover_size_normal"
android:layout_height="@dimen/cover_size_normal"
android:contentDescription="@{@string/description_album_cover(album.name)}"
app:coverArt="@{album}"
app:layout_constraintBottom_toBottomOf="parent"

View file

@ -7,7 +7,7 @@
<variable
name="genre"
type="org.oxycblt.auxio.music.models.Genre" />
type="org.oxycblt.auxio.music.Genre" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout

View file

@ -7,7 +7,7 @@
<variable
name="artist"
type="org.oxycblt.auxio.music.models.Artist" />
type="org.oxycblt.auxio.music.Artist" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@ -20,8 +20,8 @@
<ImageView
android:id="@+id/artist_image"
android:layout_width="@dimen/cover_size_large"
android:layout_height="@dimen/cover_size_large"
android:layout_width="@dimen/cover_size_normal"
android:layout_height="@dimen/cover_size_normal"
android:contentDescription="@{@string/description_artist_image(artist.name)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"

View file

@ -7,7 +7,7 @@
<variable
name="song"
type="org.oxycblt.auxio.music.models.Song" />
type="org.oxycblt.auxio.music.Song" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout