- migrated ids from `int` to `long`

- some cleaning
main
Eugeniu Olog 2020-09-17 23:25:41 +02:00
parent 90bca59192
commit 9e46d74507
58 changed files with 708 additions and 635 deletions

View File

@ -162,14 +162,14 @@ private val viewModules = module {
LibraryViewModel(get()) LibraryViewModel(get())
} }
viewModel { (albumId: Int) -> viewModel { (albumId: Long) ->
AlbumDetailsViewModel( AlbumDetailsViewModel(
get(), get(),
albumId albumId
) )
} }
viewModel { (artistId: Int) -> viewModel { (artistId: Long) ->
ArtistDetailsViewModel( ArtistDetailsViewModel(
get(), get(),
artistId artistId

View File

@ -97,8 +97,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
MusicPlayerRemote.playFromUri(uri) MusicPlayerRemote.playFromUri(uri)
handled = true handled = true
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt() val id = parseLongFromIntent(intent, "playlistId", "playlist")
if (id >= 0) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
val songs: List<Song> = val songs: List<Song> =
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id) PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
@ -106,19 +106,19 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
handled = true handled = true
} }
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "albumId", "album").toInt() val id = parseLongFromIntent(intent, "albumId", "album")
if (id >= 0) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue( MusicPlayerRemote.openQueue(
libraryViewModel.albumById(id).songs!!, libraryViewModel.albumById(id).songs,
position, position,
true true
) )
handled = true handled = true
} }
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt() val id = parseLongFromIntent(intent, "artistId", "artist")
if (id >= 0) { if (id >= 0L) {
val position: Int = intent.getIntExtra("position", 0) val position: Int = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue( MusicPlayerRemote.openQueue(
libraryViewModel.artistById(id).songs, libraryViewModel.artistById(id).songs,
@ -135,7 +135,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
private fun parseIdFromIntent( private fun parseLongFromIntent(
intent: Intent, longKey: String, intent: Intent, longKey: String,
stringKey: String stringKey: String
): Long { ): Long {

View File

@ -40,7 +40,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
val repository by inject<Repository>() val repository by inject<Repository>()
lateinit var saveFab: MaterialButton lateinit var saveFab: MaterialButton
protected var id: Int = 0 protected var id: Long = 0
private set private set
private var paletteColorPrimary: Int = 0 private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false private var isInNoImageMode: Boolean = false
@ -251,7 +251,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun getIntentExtras() { private fun getIntentExtras() {
val intentExtras = intent.extras val intentExtras = intent.extras
if (intentExtras != null) { if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID) id = intentExtras.getLong(EXTRA_ID)
} }
} }
@ -396,7 +396,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?) class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
companion object { companion object {

View File

@ -18,6 +18,7 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ImageUtil import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor import code.name.monkey.retromusic.util.RetroColorUtil.getColor
@ -168,12 +169,8 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
} }
override fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> {
val songs = repository.albumById(id).songs return repository.albumById(id).songs
val paths = ArrayList<String>(songs!!.size) .map(Song::data)
for (song in songs) {
paths.add(song.data)
}
return paths
} }
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {

View File

@ -71,13 +71,13 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position); CategoryInfo categoryInfo = categoryInfos.get(position);
holder.checkBox.setChecked(categoryInfo.visible); holder.checkBox.setChecked(categoryInfo.isVisible());
holder.title.setText(holder.title.getResources().getString(categoryInfo.category.stringRes)); holder.title.setText(holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
holder.itemView.setOnClickListener(v -> { holder.itemView.setOnClickListener(v -> {
if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) { if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
categoryInfo.visible = !categoryInfo.visible; categoryInfo.setVisible(!categoryInfo.isVisible());
holder.checkBox.setChecked(categoryInfo.visible); holder.checkBox.setChecked(categoryInfo.isVisible());
} else { } else {
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
@ -110,9 +110,9 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
} }
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) { private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
if (categoryInfo.visible) { if (categoryInfo.isVisible()) {
for (CategoryInfo c : categoryInfos) { for (CategoryInfo c : categoryInfos) {
if (c != categoryInfo && c.visible) { if (c != categoryInfo && c.isVisible()) {
return false; return false;
} }
} }

View File

@ -233,7 +233,7 @@ class HomeAdapter(
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false) fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
override fun onArtist(artistId: Int, imageView: ImageView) { override fun onArtist(artistId: Long, imageView: ImageView) {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment, R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId), bundleOf(EXTRA_ARTIST_ID to artistId),
@ -244,7 +244,7 @@ class HomeAdapter(
) )
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Long, view: View) {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId), bundleOf(EXTRA_ALBUM_ID to albumId),

View File

@ -13,7 +13,7 @@ interface HistoryDao {
suspend fun insertSongInHistory(historyEntity: HistoryEntity) suspend fun insertSongInHistory(historyEntity: HistoryEntity)
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1") @Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
suspend fun isSongPresentInHistory(songId: Int): HistoryEntity? suspend fun isSongPresentInHistory(songId: Long): HistoryEntity?
@Update @Update
suspend fun updateHistorySong(historyEntity: HistoryEntity) suspend fun updateHistorySong(historyEntity: HistoryEntity)

View File

@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
@Entity @Entity
class HistoryEntity( class HistoryEntity(
@PrimaryKey @PrimaryKey
val id: Int, val id: Long,
val title: String, val title: String,
@ColumnInfo(name = "track_number") @ColumnInfo(name = "track_number")
val trackNumber: Int, val trackNumber: Int,
@ -17,11 +17,11 @@ class HistoryEntity(
@ColumnInfo(name = "date_modified") @ColumnInfo(name = "date_modified")
val dateModified: Long, val dateModified: Long,
@ColumnInfo(name = "album_id") @ColumnInfo(name = "album_id")
val albumId: Int, val albumId: Long,
@ColumnInfo(name = "album_name") @ColumnInfo(name = "album_name")
val albumName: String, val albumName: String,
@ColumnInfo(name = "artist_id") @ColumnInfo(name = "artist_id")
val artistId: Int, val artistId: Long,
@ColumnInfo(name = "artist_name") @ColumnInfo(name = "artist_name")
val artistName: String, val artistName: String,
val composer: String?, val composer: String?,

View File

@ -14,14 +14,14 @@ interface PlayCountDao {
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId") @Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
fun playCountSongs(): List<PlayCountEntity> fun playCountSongs(): List<PlayCountEntity>
@Query("DELETE FROM SongEntity WHERE id =:songId") @Query("DELETE FROM SongEntity WHERE id =:songId")
fun deleteSong(songId: Int) fun deleteSong(songId: Long)
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id") @Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
fun updateQuantity(id: Int) fun updateQuantity(id: Long)
} }

View File

@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
@Entity @Entity
class PlayCountEntity( class PlayCountEntity(
@PrimaryKey @PrimaryKey
val id: Int, val id: Long,
val title: String, val title: String,
@ColumnInfo(name = "track_number") @ColumnInfo(name = "track_number")
val trackNumber: Int, val trackNumber: Int,
@ -17,11 +17,11 @@ class PlayCountEntity(
@ColumnInfo(name = "date_modified") @ColumnInfo(name = "date_modified")
val dateModified: Long, val dateModified: Long,
@ColumnInfo(name = "album_id") @ColumnInfo(name = "album_id")
val albumId: Int, val albumId: Long,
@ColumnInfo(name = "album_name") @ColumnInfo(name = "album_name")
val albumName: String, val albumName: String,
@ColumnInfo(name = "artist_id") @ColumnInfo(name = "artist_id")
val artistId: Int, val artistId: Long,
@ColumnInfo(name = "artist_name") @ColumnInfo(name = "artist_name")
val artistName: String, val artistName: String,
val composer: String?, val composer: String?,

View File

@ -9,7 +9,7 @@ interface PlaylistDao {
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId") @Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
suspend fun renamePlaylist(playlistId: Int, name: String) suspend fun renamePlaylist(playlistId: Long, name: String)
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name") @Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
fun isPlaylistExists(name: String): List<PlaylistEntity> fun isPlaylistExists(name: String): List<PlaylistEntity>
@ -18,10 +18,10 @@ interface PlaylistDao {
suspend fun playlists(): List<PlaylistEntity> suspend fun playlists(): List<PlaylistEntity>
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId") @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
suspend fun deletePlaylistSongs(playlistId: Int) suspend fun deletePlaylistSongs(playlistId: Long)
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId") @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int) suspend fun deleteSongFromPlaylist(playlistId: Long, songId: Long)
@Transaction @Transaction
@Query("SELECT * FROM PlaylistEntity") @Query("SELECT * FROM PlaylistEntity")
@ -31,10 +31,10 @@ interface PlaylistDao {
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>) suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List<SongEntity> suspend fun isSongExistsInPlaylist(playlistId: Long, songId: Long): List<SongEntity>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
fun songsFromPlaylist(playlistId: Int): LiveData<List<SongEntity>> fun songsFromPlaylist(playlistId: Long): LiveData<List<SongEntity>>
@Delete @Delete
suspend fun deletePlaylist(playlistEntity: PlaylistEntity) suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
@ -47,10 +47,10 @@ interface PlaylistDao {
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongsLiveData(playlistId: Int): LiveData<List<SongEntity>> fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongs(playlistId: Int): List<SongEntity> fun favoritesSongs(playlistId: Long): List<SongEntity>
} }

View File

@ -9,10 +9,9 @@ import kotlinx.android.parcel.Parcelize
@Entity @Entity
@Parcelize @Parcelize
class PlaylistEntity( class PlaylistEntity(
@ColumnInfo(name = "playlist_name")
val playlistName: String
) : Parcelable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "playlist_id") @ColumnInfo(name = "playlist_id")
var playListId: Int = 0 val playListId: Long = 0,
} @ColumnInfo(name = "playlist_name")
val playlistName: String
) : Parcelable

View File

@ -10,9 +10,12 @@ import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)]) @Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)])
class SongEntity( class SongEntity(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "song_key")
val songPrimaryKey: Long = 0L,
@ColumnInfo(name = "playlist_creator_id") @ColumnInfo(name = "playlist_creator_id")
val playlistCreatorId: Int, val playlistCreatorId: Long,
val id: Int, val id: Long,
val title: String, val title: String,
@ColumnInfo(name = "track_number") @ColumnInfo(name = "track_number")
val trackNumber: Int, val trackNumber: Int,
@ -22,19 +25,15 @@ class SongEntity(
@ColumnInfo(name = "date_modified") @ColumnInfo(name = "date_modified")
val dateModified: Long, val dateModified: Long,
@ColumnInfo(name = "album_id") @ColumnInfo(name = "album_id")
val albumId: Int, val albumId: Long,
@ColumnInfo(name = "album_name") @ColumnInfo(name = "album_name")
val albumName: String, val albumName: String,
@ColumnInfo(name = "artist_id") @ColumnInfo(name = "artist_id")
val artistId: Int, val artistId: Long,
@ColumnInfo(name = "artist_name") @ColumnInfo(name = "artist_name")
val artistName: String, val artistName: String,
val composer: String?, val composer: String?,
@ColumnInfo(name = "album_artist") @ColumnInfo(name = "album_artist")
val albumArtist: String? val albumArtist: String?
) : Parcelable { ) : Parcelable
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "song_key")
var songPrimaryKey: Long = 0
}

View File

@ -8,7 +8,7 @@ fun List<SongEntity>.toSongs(): List<Song> {
} }
} }
fun List<Song>.toSongs(playlistId: Int): List<SongEntity> { fun List<Song>.toSongs(playlistId: Long): List<SongEntity> {
return map { return map {
it.toSongEntity(playlistId) it.toSongEntity(playlistId)
} }
@ -16,75 +16,75 @@ fun List<Song>.toSongs(playlistId: Int): List<SongEntity> {
fun SongEntity.toSong(): Song { fun SongEntity.toSong(): Song {
return Song( return Song(
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist albumArtist = albumArtist
) )
} }
fun PlayCountEntity.toSong(): Song { fun PlayCountEntity.toSong(): Song {
return Song( return Song(
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist albumArtist = albumArtist
) )
} }
fun HistoryEntity.toSong(): Song { fun HistoryEntity.toSong(): Song {
return Song( return Song(
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist albumArtist = albumArtist
) )
} }
fun Song.toPlayCount(): PlayCountEntity { fun Song.toPlayCount(): PlayCountEntity {
return PlayCountEntity( return PlayCountEntity(
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist, albumArtist = albumArtist,
System.currentTimeMillis(), timePlayed = System.currentTimeMillis(),
1 playCount = 1
) )
} }

View File

@ -56,8 +56,8 @@ class CreatePlaylistDialog : DialogFragment() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) { if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
val playlistId: Long = val playlistId: Long =
libraryViewModel.createPlaylist(PlaylistEntity(playlistName)) libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlistName))
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) })
libraryViewModel.forceReload(Playlists) libraryViewModel.forceReload(Playlists)
} else { } else {
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)

View File

@ -0,0 +1,37 @@
package code.name.monkey.retromusic.extensions
import android.database.Cursor
// exception is rethrown manually in order to have a readable stacktrace
internal fun Cursor.getInt(columnName: String): Int {
try {
return this.getInt(this.getColumnIndex(columnName))
} catch (ex: Throwable) {
throw IllegalStateException("invalid column $columnName", ex)
}
}
internal fun Cursor.getLong(columnName: String): Long {
try {
return this.getLong(this.getColumnIndex(columnName))
} catch (ex: Throwable) {
throw IllegalStateException("invalid column $columnName", ex)
}
}
internal fun Cursor.getString(columnName: String): String {
try {
return this.getString(this.getColumnIndex(columnName))
} catch (ex: Throwable) {
throw IllegalStateException("invalid column $columnName", ex)
}
}
internal fun Cursor.getStringOrNull(columnName: String): String? {
try {
return this.getString(this.getColumnIndex(columnName))
} catch (ex: Throwable) {
throw IllegalStateException("invalid column $columnName", ex)
}
}

View File

@ -178,11 +178,11 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false) GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
override fun onArtist(artistId: Int, imageView: ImageView) { override fun onArtist(artistId: Long, imageView: ImageView) {
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Long, view: View) {
} }
} }

View File

@ -177,7 +177,7 @@ class LibraryViewModel(
) )
} }
fun renameRoomPlaylist(playListId: Int, name: String) = viewModelScope.launch(IO) { fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
repository.renameRoomPlaylist(playListId, name) repository.renameRoomPlaylist(playListId, name)
} }
@ -193,8 +193,8 @@ class LibraryViewModel(
repository.deleteRoomPlaylist(playlists) repository.deleteRoomPlaylist(playlists)
} }
suspend fun albumById(id: Int) = repository.albumById(id) suspend fun albumById(id: Long) = repository.albumById(id)
suspend fun artistById(id: Int) = repository.artistById(id) suspend fun artistById(id: Long) = repository.artistById(id)
suspend fun favoritePlaylist() = repository.favoritePlaylist() suspend fun favoritePlaylist() = repository.favoritePlaylist()
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song) suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs) suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs)
@ -217,9 +217,9 @@ class LibraryViewModel(
} }
repository.insertSongs(songEntities) repository.insertSongs(songEntities)
} else { } else {
val playListId = createPlaylist(PlaylistEntity(playlist.name)) val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name))
val songEntities = playlist.getSongs().map { val songEntities = playlist.getSongs().map {
it.toSongEntity(playListId.toInt()) it.toSongEntity(playListId)
} }
repository.insertSongs(songEntities) repository.insertSongs(songEntities)
} }

View File

@ -254,7 +254,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
playAction.applyOutlineColor(color) playAction.applyOutlineColor(color)
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Long, view: View) {
findNavController().navigate( findNavController().navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId) bundleOf(EXTRA_ALBUM_ID to albumId)
@ -349,29 +349,31 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
private fun setSaveSortOrder(sortOrder: String) { private fun setSaveSortOrder(sortOrder: String) {
PreferenceUtil.albumDetailSongSortOrder = sortOrder PreferenceUtil.albumDetailSongSortOrder = sortOrder
when (sortOrder) { val songs = when (sortOrder) {
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
o1.trackNumber.compareTo( o1.trackNumber.compareTo(
o2.trackNumber o2.trackNumber
) )
}) }
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
o1.title.compareTo( o1.title.compareTo(
o2.title o2.title
) )
}) }
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
o2.title.compareTo( o2.title.compareTo(
o1.title o1.title
) )
}) }
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
o1.duration.compareTo( o1.duration.compareTo(
o2.duration o2.duration
) )
})
} }
album.songs?.let { simpleSongAdapter.swapDataSet(it) } else -> throw IllegalArgumentException("invalid $sortOrder")
}
album = album.copy(songs = songs)
simpleSongAdapter.swapDataSet(album.songs)
} }
companion object { companion object {

View File

@ -13,14 +13,14 @@ import kotlinx.coroutines.Dispatchers.IO
class AlbumDetailsViewModel( class AlbumDetailsViewModel(
private val repository: RealRepository, private val repository: RealRepository,
private val albumId: Int private val albumId: Long
) : ViewModel(), MusicServiceEventListener { ) : ViewModel(), MusicServiceEventListener {
fun getAlbum(): LiveData<Album> = liveData(IO) { fun getAlbum(): LiveData<Album> = liveData(IO) {
emit(repository.albumByIdAsync(albumId)) emit(repository.albumByIdAsync(albumId))
} }
fun getArtist(artistId: Int): LiveData<Artist> = liveData(IO) { fun getArtist(artistId: Long): LiveData<Artist> = liveData(IO) {
val artist = repository.artistById(artistId) val artist = repository.artistById(artistId)
emit(artist) emit(artist)
} }
@ -31,7 +31,7 @@ class AlbumDetailsViewModel(
} }
fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) { fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) {
artist.albums?.filter { item -> item.id != albumId }?.let { albums -> artist.albums.filter { item -> item.id != albumId }.let { albums ->
if (albums.isNotEmpty()) emit(albums) if (albums.isNotEmpty()) emit(albums)
} }
} }

View File

@ -97,7 +97,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
} }
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Long, view: View) {
findActivityNavController(R.id.fragment_container).navigate( findActivityNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId), bundleOf(EXTRA_ALBUM_ID to albumId),
@ -285,5 +285,5 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
} }
interface AlbumClickListener { interface AlbumClickListener {
fun onAlbumClick(albumId: Int, view: View) fun onAlbumClick(albumId: Long, view: View)
} }

View File

@ -206,7 +206,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Long, view: View) {
findNavController().navigate( findNavController().navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId), bundleOf(EXTRA_ALBUM_ID to albumId),

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.Dispatchers.IO
class ArtistDetailsViewModel( class ArtistDetailsViewModel(
private val realRepository: RealRepository, private val realRepository: RealRepository,
private val artistId: Int private val artistId: Long
) : ViewModel(), MusicServiceEventListener { ) : ViewModel(), MusicServiceEventListener {
fun getArtist(): LiveData<Artist> = liveData(IO) { fun getArtist(): LiveData<Artist> = liveData(IO) {

View File

@ -96,7 +96,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
} }
} }
override fun onArtist(artistId: Int, imageView: ImageView) { override fun onArtist(artistId: Long, imageView: ImageView) {
val controller = findActivityNavController(R.id.fragment_container) val controller = findActivityNavController(R.id.fragment_container)
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId)) controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
} }
@ -258,5 +258,5 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
} }
interface ArtistClickListener { interface ArtistClickListener {
fun onArtist(artistId: Int, imageView: ImageView) fun onArtist(artistId: Long, imageView: ImageView)
} }

View File

@ -50,9 +50,9 @@ class ImportPlaylistFragment :
if (playlist.name.isNotEmpty()) { if (playlist.name.isNotEmpty()) {
if (libraryViewModel.checkPlaylistExists(playlist.name).isEmpty()) { if (libraryViewModel.checkPlaylistExists(playlist.name).isEmpty()) {
val playlistId: Long = val playlistId: Long =
libraryViewModel.createPlaylist(PlaylistEntity(playlist.name)) libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlist.name))
libraryViewModel.insertSongs(playlist.getSongs().map { libraryViewModel.insertSongs(playlist.getSongs().map {
it.toSongEntity(playlistId.toInt()) it.toSongEntity(playlistId)
}) })
libraryViewModel.forceReload(Playlists) libraryViewModel.forceReload(Playlists)
} else { } else {

View File

@ -7,8 +7,8 @@ import org.koin.core.KoinComponent
import org.koin.core.inject import org.koin.core.inject
abstract class AbsCustomPlaylist( abstract class AbsCustomPlaylist(
id: Int = -1, id: Long,
name: String = "" name: String
) : Playlist(id, name), KoinComponent { ) : Playlist(id, name), KoinComponent {
abstract fun songs(): List<Song> abstract fun songs(): List<Song>

View File

@ -14,19 +14,15 @@
package code.name.monkey.retromusic.model package code.name.monkey.retromusic.model
import java.util.* data class Album(
val id: Long,
class Album { val songs: List<Song>
) {
val songs: ArrayList<Song>?
val id: Int
get() = safeGetFirstSong().albumId
val title: String? val title: String?
get() = safeGetFirstSong().albumName get() = safeGetFirstSong().albumName
val artistId: Int val artistId: Long
get() = safeGetFirstSong().artistId get() = safeGetFirstSong().artistId
val artistName: String? val artistName: String?
@ -39,20 +35,17 @@ class Album {
get() = safeGetFirstSong().dateModified get() = safeGetFirstSong().dateModified
val songCount: Int val songCount: Int
get() = songs!!.size get() = songs.size
val albumArtist: String? val albumArtist: String?
get() = safeGetFirstSong().albumArtist get() = safeGetFirstSong().albumArtist
constructor(songs: ArrayList<Song>) {
this.songs = songs
}
constructor() {
this.songs = ArrayList()
}
fun safeGetFirstSong(): Song { fun safeGetFirstSong(): Song {
return if (songs!!.isEmpty()) Song.emptySong else songs[0] return songs.firstOrNull() ?: Song.emptySong
} }
companion object {
val empty = Album(-1, emptyList())
}
} }

View File

@ -17,11 +17,10 @@ package code.name.monkey.retromusic.model
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import java.util.* import java.util.*
class Artist { data class Artist(
val albums: ArrayList<Album>? val id: Long,
val albums: List<Album>
val id: Int ) {
get() = safeGetFirstAlbum().artistId
val name: String val name: String
get() { get() {
@ -34,37 +33,25 @@ class Artist {
val songCount: Int val songCount: Int
get() { get() {
var songCount = 0 var songCount = 0
for (album in albums!!) { for (album in albums) {
songCount += album.songCount songCount += album.songCount
} }
return songCount return songCount
} }
val albumCount: Int val albumCount: Int
get() = albums!!.size get() = albums.size
val songs: ArrayList<Song> val songs: List<Song>
get() { get() = albums.flatMap { it.songs }
val songs = ArrayList<Song>()
for (album in albums!!) {
songs.addAll(album.songs!!)
}
return songs
}
constructor(albums: ArrayList<Album>) {
this.albums = albums
}
constructor() {
this.albums = ArrayList()
}
fun safeGetFirstAlbum(): Album { fun safeGetFirstAlbum(): Album {
return if (albums!!.isEmpty()) Album() else albums[0] return albums.firstOrNull() ?: Album.empty
} }
companion object { companion object {
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist" const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
val empty = Artist(-1, emptyList())
} }
} }

View File

@ -1,82 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.model;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
import code.name.monkey.retromusic.R;
public class CategoryInfo implements Parcelable {
public static final Creator<CategoryInfo> CREATOR = new Creator<CategoryInfo>() {
public CategoryInfo createFromParcel(Parcel source) {
return new CategoryInfo(source);
}
public CategoryInfo[] newArray(int size) {
return new CategoryInfo[size];
}
};
public Category category;
public boolean visible;
public CategoryInfo(Category category, boolean visible) {
this.category = category;
this.visible = visible;
}
private CategoryInfo(Parcel source) {
category = (Category) source.readSerializable();
visible = source.readInt() == 1;
}
@Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(category);
dest.writeInt(visible ? 1 : 0);
}
public enum Category {
Home(R.id.action_home, R.string.for_you, R.drawable.ic_face),
Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack),
Albums(R.id.action_album, R.string.albums, R.drawable.ic_album),
Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist),
Playlists(R.id.action_playlist, R.string.playlists, (R.drawable.ic_queue_music)),
Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar),
Folder(R.id.action_folder, R.string.folders, R.drawable.ic_folder);
public final int icon;
public final int id;
public final int stringRes;
Category(int id, @StringRes int stringRes, @DrawableRes int icon) {
this.stringRes = stringRes;
this.id = id;
this.icon = icon;
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.model
import android.os.Parcelable
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import code.name.monkey.retromusic.R
import kotlinx.android.parcel.Parcelize
@Parcelize
data class CategoryInfo(
val category: Category,
@get:JvmName("isVisible")
var visible: Boolean
) : Parcelable {
enum class Category(
val id: Int,
@StringRes val stringRes: Int,
@DrawableRes val icon: Int
) {
Home(R.id.action_home, R.string.for_you, R.drawable.ic_face),
Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack),
Albums(R.id.action_album, R.string.albums, R.drawable.ic_album),
Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist),
Playlists(R.id.action_playlist, R.string.playlists, R.drawable.ic_queue_music),
Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar),
Folder(R.id.action_folder, R.string.folders, R.drawable.ic_folder);
}
}

View File

@ -16,8 +16,10 @@ package code.name.monkey.retromusic.model
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
class Contributor( data class Contributor(
val name: String, val name: String,
val summary: String, val summary: String,
val link: String, @SerializedName("profile_image") val profileImage: String val link: String,
@SerializedName("profile_image")
val profileImage: String
) )

View File

@ -18,4 +18,8 @@ import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
data class Genre(val id: Int = -1, val name: String, val songCount: Int) : Parcelable data class Genre(
val id: Long,
val name: String,
val songCount: Int
) : Parcelable

View File

@ -17,7 +17,7 @@ package code.name.monkey.retromusic.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import code.name.monkey.retromusic.HomeSection import code.name.monkey.retromusic.HomeSection
class Home( data class Home(
val arrayList: List<Any>, val arrayList: List<Any>,
@HomeSection @HomeSection
val homeSection: Int, val homeSection: Int,

View File

@ -10,10 +10,14 @@ import org.koin.core.get
@Parcelize @Parcelize
open class Playlist( open class Playlist(
val id: Int = -1, val id: Long,
val name: String = "" val name: String
) : Parcelable, KoinComponent { ) : Parcelable, KoinComponent {
companion object {
val empty = Playlist(-1, "")
}
// this default implementation covers static playlists // this default implementation covers static playlists
fun getSongs(): List<Song> { fun getSongs(): List<Song> {
return RealPlaylistRepository(get()).playlistSongs(id) return RealPlaylistRepository(get()).playlistSongs(id)
@ -27,4 +31,24 @@ open class Playlist(
"" ""
) )
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Playlist
if (id != other.id) return false
if (name != other.name) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + name.hashCode()
return result
}
} }

View File

@ -1,58 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.model;
import org.jetbrains.annotations.NotNull;
import kotlinx.android.parcel.Parcelize;
/**
* Created by hemanths on 3/4/19
*/
@Parcelize
public class PlaylistSong extends Song {
final int idInPlayList;
final int playlistId;
public PlaylistSong(int id,
@NotNull String title,
int trackNumber,
int year,
long duration,
@NotNull String data,
long dateModified,
int albumId,
@NotNull String albumName,
int artistId,
@NotNull String artistName,
int playlistId,
int idInPlayList,
@NotNull String composer,
String albumArtist) {
super(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName, composer, albumArtist);
this.playlistId = playlistId;
this.idInPlayList = idInPlayList;
}
public int getIdInPlayList() {
return idInPlayList;
}
public int getPlaylistId() {
return playlistId;
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.model
import kotlinx.android.parcel.Parcelize
/**
* Created by hemanths on 3/4/19
*/
@Parcelize
class PlaylistSong(
override val id: Long,
override val title: String,
override val trackNumber: Int,
override val year: Int,
override val duration: Long,
override val data: String,
override val dateModified: Long,
override val albumId: Long,
override val albumName: String,
override val artistId: Long,
override val artistName: String,
val playlistId: Long,
val idInPlayList: Long,
override val composer: String,
override val albumArtist: String?
) : Song(
id = id,
title = title,
trackNumber = trackNumber,
year = year,
duration = duration,
data = data,
dateModified = dateModified,
albumId = albumId,
albumName = albumName,
artistId = artistId,
artistName = artistName,
composer = composer,
albumArtist = albumArtist
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
if (!super.equals(other)) return false
other as PlaylistSong
if (id != other.id) return false
if (title != other.title) return false
if (trackNumber != other.trackNumber) return false
if (year != other.year) return false
if (duration != other.duration) return false
if (data != other.data) return false
if (dateModified != other.dateModified) return false
if (albumId != other.albumId) return false
if (albumName != other.albumName) return false
if (artistId != other.artistId) return false
if (artistName != other.artistName) return false
if (playlistId != other.playlistId) return false
if (idInPlayList != other.idInPlayList) return false
if (composer != other.composer) return false
if (albumArtist != other.albumArtist) return false
return true
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + id.hashCode()
result = 31 * result + title.hashCode()
result = 31 * result + trackNumber
result = 31 * result + year
result = 31 * result + duration.hashCode()
result = 31 * result + data.hashCode()
result = 31 * result + dateModified.hashCode()
result = 31 * result + albumId.hashCode()
result = 31 * result + albumName.hashCode()
result = 31 * result + artistId.hashCode()
result = 31 * result + artistName.hashCode()
result = 31 * result + playlistId.hashCode()
result = 31 * result + idInPlayList.hashCode()
result = 31 * result + composer.hashCode()
result = 31 * result + (albumArtist?.hashCode() ?: 0)
return result
}
}

View File

@ -18,78 +18,120 @@ import code.name.monkey.retromusic.db.HistoryEntity
import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.SongEntity
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
// update equals and hashcode if fields changes
@Parcelize @Parcelize
open class Song( open class Song(
val id: Int, open val id: Long,
val title: String, open val title: String,
val trackNumber: Int, open val trackNumber: Int,
val year: Int, open val year: Int,
val duration: Long, open val duration: Long,
val data: String, open val data: String,
val dateModified: Long, open val dateModified: Long,
val albumId: Int, open val albumId: Long,
val albumName: String, open val albumName: String,
val artistId: Int, open val artistId: Long,
val artistName: String, open val artistName: String,
val composer: String?, open val composer: String?,
val albumArtist: String? open val albumArtist: String?
) : Parcelable { ) : Parcelable {
fun toHistoryEntity(timePlayed: Long): HistoryEntity { fun toHistoryEntity(timePlayed: Long): HistoryEntity {
return HistoryEntity( return HistoryEntity(
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist, albumArtist = albumArtist,
timePlayed timePlayed = timePlayed
) )
} }
fun toSongEntity(playListId: Int): SongEntity { fun toSongEntity(playListId: Long): SongEntity {
return SongEntity( return SongEntity(
playListId, playlistCreatorId = playListId,
id, id = id,
title, title = title,
trackNumber, trackNumber = trackNumber,
year, year = year,
duration, duration = duration,
data, data = data,
dateModified, dateModified = dateModified,
albumId, albumId = albumId,
albumName, albumName = albumName,
artistId, artistId = artistId,
artistName, artistName = artistName,
composer, composer = composer,
albumArtist albumArtist = albumArtist
) )
} }
// need to override manually because is open and cannot be a data class
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Song
if (id != other.id) return false
if (title != other.title) return false
if (trackNumber != other.trackNumber) return false
if (year != other.year) return false
if (duration != other.duration) return false
if (data != other.data) return false
if (dateModified != other.dateModified) return false
if (albumId != other.albumId) return false
if (albumName != other.albumName) return false
if (artistId != other.artistId) return false
if (artistName != other.artistName) return false
if (composer != other.composer) return false
if (albumArtist != other.albumArtist) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + title.hashCode()
result = 31 * result + trackNumber
result = 31 * result + year
result = 31 * result + duration.hashCode()
result = 31 * result + data.hashCode()
result = 31 * result + dateModified.hashCode()
result = 31 * result + albumId.hashCode()
result = 31 * result + albumName.hashCode()
result = 31 * result + artistId.hashCode()
result = 31 * result + artistName.hashCode()
result = 31 * result + (composer?.hashCode() ?: 0)
result = 31 * result + (albumArtist?.hashCode() ?: 0)
return result
}
companion object { companion object {
@JvmStatic @JvmStatic
val emptySong = Song( val emptySong = Song(
-1, id = -1,
"", title = "",
-1, trackNumber = -1,
-1, year = -1,
-1, duration = -1,
"", data = "",
-1, dateModified = -1,
-1, albumId = -1,
"", albumName = "",
-1, artistId = -1,
"", artistName = "",
"", composer = "",
"" albumArtist = ""
) )
} }
} }

View File

@ -5,6 +5,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.AbsCustomPlaylist
abstract class AbsSmartPlaylist( abstract class AbsSmartPlaylist(
name: String = "", name: String,
@DrawableRes val iconRes: Int = R.drawable.ic_queue_music @DrawableRes val iconRes: Int = R.drawable.ic_queue_music
) : AbsCustomPlaylist(-Math.abs(31 * name.hashCode() + iconRes * name.hashCode() * 31 * 31), name) ) : AbsCustomPlaylist(
id = PlaylistIdGenerator(name, iconRes),
name = name
)

View File

@ -7,12 +7,11 @@ import kotlinx.android.parcel.Parcelize
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
@Parcelize @Parcelize
class HistoryPlaylist : class HistoryPlaylist : AbsSmartPlaylist(
AbsSmartPlaylist( name = App.getContext().getString(R.string.history),
App.getContext().getString(R.string.history), iconRes = R.drawable.ic_history
R.drawable.ic_history ), KoinComponent {
),
KoinComponent {
override fun songs(): List<Song> { override fun songs(): List<Song> {
return topPlayedRepository.recentlyPlayedTracks() return topPlayedRepository.recentlyPlayedTracks()
} }

View File

@ -6,8 +6,10 @@ import code.name.monkey.retromusic.model.Song
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
class LastAddedPlaylist : class LastAddedPlaylist : AbsSmartPlaylist(
AbsSmartPlaylist(App.getContext().getString(R.string.last_added), R.drawable.ic_library_add) { name = App.getContext().getString(R.string.last_added),
iconRes = R.drawable.ic_library_add
) {
override fun songs(): List<Song> { override fun songs(): List<Song> {
return lastAddedRepository.recentSongs() return lastAddedRepository.recentSongs()
} }

View File

@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
class NotPlayedPlaylist : AbsSmartPlaylist( class NotPlayedPlaylist : AbsSmartPlaylist(
App.getContext().getString(R.string.not_recently_played), name = App.getContext().getString(R.string.not_recently_played),
R.drawable.ic_watch_later iconRes = R.drawable.ic_watch_later
) { ) {
override fun songs(): List<Song> { override fun songs(): List<Song> {
return topPlayedRepository.notRecentlyPlayedTracks() return topPlayedRepository.notRecentlyPlayedTracks()

View File

@ -0,0 +1,12 @@
package code.name.monkey.retromusic.model.smartplaylist
import androidx.annotation.DrawableRes
import kotlin.math.abs
object PlaylistIdGenerator {
operator fun invoke(name: String, @DrawableRes iconRes: Int): Long {
return -abs(31L * name.hashCode() + iconRes * name.hashCode() * 31L * 31L)
}
}

View File

@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
class ShuffleAllPlaylist : AbsSmartPlaylist( class ShuffleAllPlaylist : AbsSmartPlaylist(
App.getContext().getString(R.string.action_shuffle_all), name = App.getContext().getString(R.string.action_shuffle_all),
R.drawable.ic_shuffle iconRes = R.drawable.ic_shuffle
) { ) {
override fun songs(): List<Song> { override fun songs(): List<Song> {
return songRepository.songs() return songRepository.songs()

View File

@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
class TopTracksPlaylist : AbsSmartPlaylist( class TopTracksPlaylist : AbsSmartPlaylist(
App.getContext().getString(R.string.my_top_tracks), name = App.getContext().getString(R.string.my_top_tracks),
R.drawable.ic_trending_up iconRes = R.drawable.ic_trending_up
) { ) {
override fun songs(): List<Song> { override fun songs(): List<Song> {
return topPlayedRepository.topTracks() return topPlayedRepository.topTracks()

View File

@ -31,7 +31,7 @@ interface AlbumRepository {
fun albums(query: String): List<Album> fun albums(query: String): List<Album>
fun album(albumId: Int): Album fun album(albumId: Long): Album
} }
class RealAlbumRepository(private val songRepository: RealSongRepository) : class RealAlbumRepository(private val songRepository: RealSongRepository) :
@ -59,70 +59,42 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
return splitIntoAlbums(songs) return splitIntoAlbums(songs)
} }
override fun album(albumId: Int): Album { override fun album(albumId: Long): Album {
val cursor = songRepository.makeSongCursor( val cursor = songRepository.makeSongCursor(
AudioColumns.ALBUM_ID + "=?", AudioColumns.ALBUM_ID + "=?",
arrayOf(albumId.toString()), arrayOf(albumId.toString()),
getSongLoaderSortOrder() getSongLoaderSortOrder()
) )
val songs = songRepository.songs(cursor) val songs = songRepository.songs(cursor)
val album = Album(ArrayList(songs)) val album = Album(albumId, songs)
sortAlbumSongs(album) sortAlbumSongs(album)
return album return album
} }
fun splitIntoAlbums( fun splitIntoAlbums(
songs: List<Song>? songs: List<Song>
): List<Album> { ): List<Album> {
val albums = ArrayList<Album>() return songs.groupBy { it.albumId }
if (songs != null) { .map { sortAlbumSongs(Album(it.key, it.value)) }
for (song in songs) {
getOrCreateAlbum(albums, song.albumId).songs?.add(song)
}
}
for (album in albums) {
sortAlbumSongs(album)
}
return albums
} }
private fun getOrCreateAlbum( private fun sortAlbumSongs(album: Album): Album {
albums: ArrayList<Album>, val songs = when (PreferenceUtil.albumDetailSongSortOrder) {
albumId: Int SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
): Album { o1.trackNumber.compareTo(o2.trackNumber)
for (album in albums) {
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) {
return album
} }
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
o1.title.compareTo(o2.title)
} }
val album = Album() SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
albums.add(album) o2.title.compareTo(o1.title)
return album
} }
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
private fun sortAlbumSongs(album: Album) { o1.duration.compareTo(o2.duration)
when (PreferenceUtil.albumDetailSongSortOrder) {
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.trackNumber.compareTo(
o2.trackNumber
)
})
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.title.compareTo(
o2.title
)
})
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
o2.title.compareTo(
o1.title
)
})
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.duration.compareTo(
o2.duration
)
})
} }
else -> throw IllegalArgumentException("invalid ${PreferenceUtil.albumDetailSongSortOrder}")
}
return album.copy(songs = songs)
} }
private fun getSongLoaderSortOrder(): String { private fun getSongLoaderSortOrder(): String {

View File

@ -26,7 +26,7 @@ interface ArtistRepository {
fun artists(query: String): List<Artist> fun artists(query: String): List<Artist>
fun artist(artistId: Int): Artist fun artist(artistId: Long): Artist
} }
class RealArtistRepository( class RealArtistRepository(
@ -73,20 +73,18 @@ class RealArtistRepository(
} }
private fun splitIntoAlbumArtists(albums: List<Album>): List<Artist> { private fun splitIntoAlbumArtists(albums: List<Album>): List<Artist> {
// First group the songs in albums by filtering each artist name return albums.groupBy { it.albumArtist }
val amap = hashMapOf<String, Artist>() .map {
albums.forEach { val currentAlbums = it.value
val key = it.albumArtist if (albums.isNotEmpty()) {
if (key != null) { Artist(currentAlbums[0].id, currentAlbums)
val artist: Artist = if (amap[key] != null) amap[key]!! else Artist() } else {
artist.albums?.add(it) Artist.empty
amap[key] = artist
} }
} }
return ArrayList(amap.values)
} }
override fun artist(artistId: Int): Artist { override fun artist(artistId: Long): Artist {
val songs = songRepository.songs( val songs = songRepository.songs(
songRepository.makeSongCursor( songRepository.makeSongCursor(
AudioColumns.ARTIST_ID + "=?", AudioColumns.ARTIST_ID + "=?",
@ -94,27 +92,12 @@ class RealArtistRepository(
getSongLoaderSortOrder() getSongLoaderSortOrder()
) )
) )
return Artist(ArrayList(albumRepository.splitIntoAlbums(songs))) return Artist(artistId, albumRepository.splitIntoAlbums(songs))
} }
fun splitIntoArtists(albums: List<Album>?): List<Artist> { fun splitIntoArtists(albums: List<Album>): List<Artist> {
val artists = mutableListOf<Artist>() return albums.groupBy { it.artistId }
if (albums != null) { .map { Artist(it.key, it.value) }
for (album in albums) {
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
}
}
return artists
} }
private fun getOrCreateArtist(artists: MutableList<Artist>, artistId: Int): Artist {
for (artist in artists) {
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
return artist
}
}
val album = Artist()
artists.add(album)
return album
}
} }

View File

@ -22,6 +22,8 @@ import android.provider.MediaStore
import android.provider.MediaStore.Audio.Genres import android.provider.MediaStore.Audio.Genres
import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.Constants.IS_MUSIC
import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -29,7 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
interface GenreRepository { interface GenreRepository {
fun genres(): List<Genre> fun genres(): List<Genre>
fun songs(genreId: Int): List<Song> fun songs(genreId: Long): List<Song>
} }
class RealGenreRepository( class RealGenreRepository(
@ -41,25 +43,25 @@ class RealGenreRepository(
return getGenresFromCursor(makeGenreCursor()) return getGenresFromCursor(makeGenreCursor())
} }
override fun songs(genreId: Int): List<Song> { override fun songs(genreId: Long): List<Song> {
// The genres table only stores songs that have a genre specified, // The genres table only stores songs that have a genre specified,
// so we need to get songs without a genre a different way. // so we need to get songs without a genre a different way.
return if (genreId == -1) { return if (genreId == -1L) {
getSongsWithNoGenre() getSongsWithNoGenre()
} else songRepository.songs(makeGenreSongCursor(genreId)) } else songRepository.songs(makeGenreSongCursor(genreId))
} }
private fun getGenreFromCursor(cursor: Cursor): Genre { private fun getGenreFromCursor(cursor: Cursor): Genre {
val id = cursor.getInt(0) val id = cursor.getLong(Genres._ID)
val name = cursor.getString(1) val name = cursor.getString(Genres.NAME)
val songCount = songs(id).size val songCount = songs(id).size
return Genre(id, name, songCount) return Genre(id, name, songCount)
} }
private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre { private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre {
val id = cursor.getInt(0) val id = cursor.getLong(Genres._ID)
val name = cursor.getString(1) val name = cursor.getString(Genres.NAME)
return Genre(id, name, -1) return Genre(id, name, -1)
} }
@ -91,9 +93,9 @@ class RealGenreRepository(
) )
} }
private fun makeGenreSongCursor(genreId: Int): Cursor? { private fun makeGenreSongCursor(genreId: Long): Cursor? {
return contentResolver.query( return contentResolver.query(
Genres.Members.getContentUri("external", genreId.toLong()), Genres.Members.getContentUri("external", genreId),
baseProjection, baseProjection,
IS_MUSIC, IS_MUSIC,
null, null,

View File

@ -18,8 +18,13 @@ import android.content.ContentResolver
import android.database.Cursor import android.database.Cursor
import android.provider.BaseColumns import android.provider.BaseColumns
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Audio.PlaylistsColumns import android.provider.MediaStore.Audio.*
import android.provider.MediaStore.Audio.Playlists.*
import code.name.monkey.retromusic.Constants import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.extensions.getInt
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.extensions.getStringOrNull
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.PlaylistSong
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
@ -40,11 +45,11 @@ interface PlaylistRepository {
fun favoritePlaylist(playlistName: String): List<Playlist> fun favoritePlaylist(playlistName: String): List<Playlist>
fun deletePlaylist(playlistId: Int) fun deletePlaylist(playlistId: Long)
fun playlist(playlistId: Int): Playlist fun playlist(playlistId: Long): Playlist
fun playlistSongs(playlistId: Int): List<Song> fun playlistSongs(playlistId: Long): List<Song>
} }
class RealPlaylistRepository( class RealPlaylistRepository(
@ -52,19 +57,20 @@ class RealPlaylistRepository(
) : PlaylistRepository { ) : PlaylistRepository {
override fun playlist(cursor: Cursor?): Playlist { override fun playlist(cursor: Cursor?): Playlist {
var playlist = Playlist() return cursor.use {
if (cursor != null && cursor.moveToFirst()) { if (cursor?.moveToFirst() == true) {
playlist = getPlaylistFromCursorImpl(cursor) getPlaylistFromCursorImpl(cursor)
} else {
Playlist.empty
}
} }
cursor?.close()
return playlist
} }
override fun playlist(playlistName: String): Playlist { override fun playlist(playlistName: String): Playlist {
return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName))) return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName)))
} }
override fun playlist(playlistId: Int): Playlist { override fun playlist(playlistId: Long): Playlist {
return playlist( return playlist(
makePlaylistCursor( makePlaylistCursor(
BaseColumns._ID + "=?", BaseColumns._ID + "=?",
@ -101,8 +107,8 @@ class RealPlaylistRepository(
) )
} }
override fun deletePlaylist(playlistId: Int) { override fun deletePlaylist(playlistId: Long) {
val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI val localUri = EXTERNAL_CONTENT_URI
val localStringBuilder = StringBuilder() val localStringBuilder = StringBuilder()
localStringBuilder.append("_id IN (") localStringBuilder.append("_id IN (")
localStringBuilder.append(playlistId) localStringBuilder.append(playlistId)
@ -113,12 +119,12 @@ class RealPlaylistRepository(
private fun getPlaylistFromCursorImpl( private fun getPlaylistFromCursorImpl(
cursor: Cursor cursor: Cursor
): Playlist { ): Playlist {
val id = cursor.getInt(0) val id = cursor.getLong(MediaStore.MediaColumns._ID)
val name = cursor.getString(1) val name = cursor.getString(NAME)
return Playlist(id, name) return Playlist(id, name)
} }
override fun playlistSongs(playlistId: Int): List<Song> { override fun playlistSongs(playlistId: Long): List<Song> {
val songs = arrayListOf<Song>() val songs = arrayListOf<Song>()
val cursor = makePlaylistSongCursor(playlistId) val cursor = makePlaylistSongCursor(playlistId)
@ -131,21 +137,21 @@ class RealPlaylistRepository(
return songs return songs
} }
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong { private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
val id = cursor.getInt(0) val id = cursor.getLong(Members.AUDIO_ID)
val title = cursor.getString(1) val title = cursor.getString(AudioColumns.TITLE)
val trackNumber = cursor.getInt(2) val trackNumber = cursor.getInt(AudioColumns.TRACK)
val year = cursor.getInt(3) val year = cursor.getInt(AudioColumns.YEAR)
val duration = cursor.getLong(4) val duration = cursor.getLong(AudioColumns.DURATION)
val data = cursor.getString(5) val data = cursor.getString(AudioColumns.DATA)
val dateModified = cursor.getLong(6) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
val albumId = cursor.getInt(7) val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
val albumName = cursor.getString(8) val albumName = cursor.getString(AudioColumns.ALBUM)
val artistId = cursor.getInt(9) val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
val artistName = cursor.getString(10) val artistName = cursor.getString(AudioColumns.ARTIST)
val idInPlaylist = cursor.getInt(11) val idInPlaylist = cursor.getLong(Members._ID)
val composer = cursor.getString(12) val composer = cursor.getString(AudioColumns.COMPOSER)
val albumArtist = cursor.getString(13) val albumArtist = cursor.getStringOrNull("album_artist")
return PlaylistSong( return PlaylistSong(
id, id,
title, title,
@ -170,37 +176,37 @@ class RealPlaylistRepository(
values: Array<String>? values: Array<String>?
): Cursor? { ): Cursor? {
return contentResolver.query( return contentResolver.query(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, EXTERNAL_CONTENT_URI,
arrayOf( arrayOf(
BaseColumns._ID, /* 0 */ BaseColumns._ID, /* 0 */
PlaylistsColumns.NAME /* 1 */ PlaylistsColumns.NAME /* 1 */
), ),
selection, selection,
values, values,
MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER DEFAULT_SORT_ORDER
) )
} }
private fun makePlaylistSongCursor(playlistId: Int): Cursor? { private fun makePlaylistSongCursor(playlistId: Long): Cursor? {
return contentResolver.query( return contentResolver.query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()), Members.getContentUri("external", playlistId),
arrayOf( arrayOf(
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0 Members.AUDIO_ID, // 0
MediaStore.Audio.AudioColumns.TITLE, // 1 AudioColumns.TITLE, // 1
MediaStore.Audio.AudioColumns.TRACK, // 2 AudioColumns.TRACK, // 2
MediaStore.Audio.AudioColumns.YEAR, // 3 AudioColumns.YEAR, // 3
MediaStore.Audio.AudioColumns.DURATION, // 4 AudioColumns.DURATION, // 4
MediaStore.Audio.AudioColumns.DATA, // 5 AudioColumns.DATA, // 5
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6 AudioColumns.DATE_MODIFIED, // 6
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7 AudioColumns.ALBUM_ID, // 7
MediaStore.Audio.AudioColumns.ALBUM, // 8 AudioColumns.ALBUM, // 8
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9 AudioColumns.ARTIST_ID, // 9
MediaStore.Audio.AudioColumns.ARTIST, // 10 AudioColumns.ARTIST, // 10
MediaStore.Audio.Playlists.Members._ID,//11 Members._ID,//11
MediaStore.Audio.AudioColumns.COMPOSER,//12 AudioColumns.COMPOSER,//12
"album_artist"//13 "album_artist"//13
), Constants.IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER ), Constants.IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
) )
} }
} }

View File

@ -18,7 +18,12 @@ import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio.AudioColumns
import android.provider.MediaStore.Audio.Playlists.*
import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.Constants.IS_MUSIC
import code.name.monkey.retromusic.extensions.getInt
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.extensions.getStringOrNull
import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.AbsCustomPlaylist
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.PlaylistSong
@ -42,7 +47,7 @@ object PlaylistSongsLoader {
} }
@JvmStatic @JvmStatic
fun getPlaylistSongList(context: Context, playlistId: Int): List<Song> { fun getPlaylistSongList(context: Context, playlistId: Long): List<Song> {
val songs = mutableListOf<Song>() val songs = mutableListOf<Song>()
val cursor = val cursor =
makePlaylistSongCursor( makePlaylistSongCursor(
@ -64,21 +69,22 @@ object PlaylistSongsLoader {
return songs return songs
} }
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong { // TODO duplicated in [PlaylistRepository.kt]
val id = cursor.getInt(0) private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
val title = cursor.getString(1) val id = cursor.getLong(Members.AUDIO_ID)
val trackNumber = cursor.getInt(2) val title = cursor.getString(AudioColumns.TITLE)
val year = cursor.getInt(3) val trackNumber = cursor.getInt(AudioColumns.TRACK)
val duration = cursor.getLong(4) val year = cursor.getInt(AudioColumns.YEAR)
val data = cursor.getString(5) val duration = cursor.getLong(AudioColumns.DURATION)
val dateModified = cursor.getLong(6) val data = cursor.getString(AudioColumns.DATA)
val albumId = cursor.getInt(7) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
val albumName = cursor.getString(8) val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
val artistId = cursor.getInt(9) val albumName = cursor.getString(AudioColumns.ALBUM)
val artistName = cursor.getString(10) val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
val idInPlaylist = cursor.getInt(11) val artistName = cursor.getString(AudioColumns.ARTIST)
val composer = cursor.getString(12) val idInPlaylist = cursor.getLong(Members._ID)
val albumArtist = cursor.getString(13) val composer = cursor.getString(AudioColumns.COMPOSER)
val albumArtist = cursor.getStringOrNull("album_artist")
return PlaylistSong( return PlaylistSong(
id, id,
title, title,
@ -98,12 +104,12 @@ object PlaylistSongsLoader {
) )
} }
private fun makePlaylistSongCursor(context: Context, playlistId: Int): Cursor? { private fun makePlaylistSongCursor(context: Context, playlistId: Long): Cursor? {
try { try {
return context.contentResolver.query( return context.contentResolver.query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()), Members.getContentUri("external", playlistId),
arrayOf( arrayOf(
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0 Members.AUDIO_ID, // 0
AudioColumns.TITLE, // 1 AudioColumns.TITLE, // 1
AudioColumns.TRACK, // 2 AudioColumns.TRACK, // 2
AudioColumns.YEAR, // 3 AudioColumns.YEAR, // 3
@ -114,10 +120,10 @@ object PlaylistSongsLoader {
AudioColumns.ALBUM, // 8 AudioColumns.ALBUM, // 8
AudioColumns.ARTIST_ID, // 9 AudioColumns.ARTIST_ID, // 9
AudioColumns.ARTIST, // 10 AudioColumns.ARTIST, // 10
MediaStore.Audio.Playlists.Members._ID,//11 Members._ID,//11
AudioColumns.COMPOSER,//12 AudioColumns.COMPOSER,//12
"album_artist"//13 "album_artist"//13
), IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER ), IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
) )
} catch (e: SecurityException) { } catch (e: SecurityException) {
return null return null

View File

@ -41,10 +41,10 @@ interface Repository {
fun historySong(): List<HistoryEntity> fun historySong(): List<HistoryEntity>
fun favorites(): LiveData<List<SongEntity>> fun favorites(): LiveData<List<SongEntity>>
fun observableHistorySongs(): LiveData<List<HistoryEntity>> fun observableHistorySongs(): LiveData<List<HistoryEntity>>
fun albumById(albumId: Int): Album fun albumById(albumId: Long): Album
fun playlistSongs(playlistEntity: PlaylistEntity): LiveData<List<SongEntity>> fun playlistSongs(playlistEntity: PlaylistEntity): LiveData<List<SongEntity>>
suspend fun fetchAlbums(): List<Album> suspend fun fetchAlbums(): List<Album>
suspend fun albumByIdAsync(albumId: Int): Album suspend fun albumByIdAsync(albumId: Long): Album
suspend fun allSongs(): List<Song> suspend fun allSongs(): List<Song>
suspend fun fetchArtists(): List<Artist> suspend fun fetchArtists(): List<Artist>
suspend fun albumArtists(): List<Artist> suspend fun albumArtists(): List<Artist>
@ -52,10 +52,10 @@ interface Repository {
suspend fun fetchGenres(): List<Genre> suspend fun fetchGenres(): List<Genre>
suspend fun search(query: String?): MutableList<Any> suspend fun search(query: String?): MutableList<Any>
suspend fun getPlaylistSongs(playlist: Playlist): List<Song> suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
suspend fun getGenre(genreId: Int): List<Song> suspend fun getGenre(genreId: Long): List<Song>
suspend fun artistInfo(name: String, lang: String?, cache: String?): Result<LastFmArtist> suspend fun artistInfo(name: String, lang: String?, cache: String?): Result<LastFmArtist>
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum> suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum>
suspend fun artistById(artistId: Int): Artist suspend fun artistById(artistId: Long): Artist
suspend fun recentArtists(): List<Artist> suspend fun recentArtists(): List<Artist>
suspend fun topArtists(): List<Artist> suspend fun topArtists(): List<Artist>
suspend fun topAlbums(): List<Album> suspend fun topAlbums(): List<Album>
@ -70,7 +70,7 @@ interface Repository {
suspend fun playlists(): Home suspend fun playlists(): Home
suspend fun homeSections(): List<Home> suspend fun homeSections(): List<Home>
suspend fun homeSectionsFlow(): Flow<Result<List<Home>>> suspend fun homeSectionsFlow(): Flow<Result<List<Home>>>
suspend fun playlist(playlistId: Int): Playlist suspend fun playlist(playlistId: Long): Playlist
suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs>
suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
suspend fun insertSongs(songs: List<SongEntity>) suspend fun insertSongs(songs: List<SongEntity>)
@ -78,7 +78,7 @@ interface Repository {
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
suspend fun fetchPlaylists(): List<PlaylistEntity> suspend fun fetchPlaylists(): List<PlaylistEntity>
suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>)
suspend fun renameRoomPlaylist(playlistId: Int, name: String) suspend fun renameRoomPlaylist(playlistId: Long, name: String)
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun removeSongFromPlaylist(songEntity: SongEntity)
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>) suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
@ -93,7 +93,7 @@ interface Repository {
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity> suspend fun playCountSongs(): List<PlayCountEntity>
suspend fun blackListPaths(): List<BlackListStoreEntity> suspend fun blackListPaths(): List<BlackListStoreEntity>
suspend fun lyrics(artist: String, title: String): Result<String> suspend fun lyrics(artist: String, title: String): Result<String>
@ -126,15 +126,15 @@ class RealRepository(
override suspend fun fetchAlbums(): List<Album> = albumRepository.albums() override suspend fun fetchAlbums(): List<Album> = albumRepository.albums()
override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) override suspend fun albumByIdAsync(albumId: Long): Album = albumRepository.album(albumId)
override fun albumById(albumId: Int): Album = albumRepository.album(albumId) override fun albumById(albumId: Long): Album = albumRepository.album(albumId)
override suspend fun fetchArtists(): List<Artist> = artistRepository.artists() override suspend fun fetchArtists(): List<Artist> = artistRepository.artists()
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists() override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
override suspend fun artistById(artistId: Int): Artist = artistRepository.artist(artistId) override suspend fun artistById(artistId: Long): Artist = artistRepository.artist(artistId)
override suspend fun recentArtists(): List<Artist> = lastAddedRepository.recentArtists() override suspend fun recentArtists(): List<Artist> = lastAddedRepository.recentArtists()
@ -160,7 +160,7 @@ class RealRepository(
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
} }
override suspend fun getGenre(genreId: Int): List<Song> = genreRepository.songs(genreId) override suspend fun getGenre(genreId: Long): List<Song> = genreRepository.songs(genreId)
override suspend fun artistInfo( override suspend fun artistInfo(
name: String, name: String,
@ -235,7 +235,7 @@ class RealRepository(
} }
override suspend fun playlist(playlistId: Int) = override suspend fun playlist(playlistId: Long) =
playlistRepository.playlist(playlistId) playlistRepository.playlist(playlistId)
override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> = override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> =
@ -263,7 +263,7 @@ class RealRepository(
override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) = override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) =
roomRepository.deletePlaylistEntities(playlists) roomRepository.deletePlaylistEntities(playlists)
override suspend fun renameRoomPlaylist(playlistId: Int, name: String) = override suspend fun renameRoomPlaylist(playlistId: Long, name: String) =
roomRepository.renamePlaylistEntity(playlistId, name) roomRepository.renamePlaylistEntity(playlistId, name)
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) = override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
@ -306,7 +306,7 @@ class RealRepository(
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
roomRepository.deleteSongInPlayCount(playCountEntity) roomRepository.deleteSongInPlayCount(playCountEntity)
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> = override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
roomRepository.checkSongExistInPlayCount(songId) roomRepository.checkSongExistInPlayCount(songId)
override suspend fun playCountSongs(): List<PlayCountEntity> = override suspend fun playCountSongs(): List<PlayCountEntity> =

View File

@ -18,7 +18,7 @@ interface RoomRepository {
suspend fun playlistWithSongs(): List<PlaylistWithSongs> suspend fun playlistWithSongs(): List<PlaylistWithSongs>
suspend fun insertSongs(songs: List<SongEntity>) suspend fun insertSongs(songs: List<SongEntity>)
suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>)
suspend fun renamePlaylistEntity(playlistId: Int, name: String) suspend fun renamePlaylistEntity(playlistId: Long, name: String)
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>) suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
suspend fun favoritePlaylist(favorite: String): PlaylistEntity suspend fun favoritePlaylist(favorite: String): PlaylistEntity
@ -31,7 +31,7 @@ interface RoomRepository {
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity> suspend fun playCountSongs(): List<PlayCountEntity>
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>) suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
@ -76,7 +76,7 @@ class RealRoomRepository(
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) = override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
playlistDao.deletePlaylists(playlistEntities) playlistDao.deletePlaylists(playlistEntities)
override suspend fun renamePlaylistEntity(playlistId: Int, name: String) = override suspend fun renamePlaylistEntity(playlistId: Long, name: String) =
playlistDao.renamePlaylist(playlistId, name) playlistDao.renamePlaylist(playlistId, name)
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) { override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) {
@ -95,7 +95,7 @@ class RealRoomRepository(
return if (playlist != null) { return if (playlist != null) {
playlist playlist
} else { } else {
createPlaylist(PlaylistEntity(favorite)) createPlaylist(PlaylistEntity(playlistName = favorite))
playlistDao.isPlaylistExists(favorite).first() playlistDao.isPlaylistExists(favorite).first()
} }
} }
@ -143,7 +143,7 @@ class RealRoomRepository(
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
playCountDao.deleteSongInPlayCount(playCountEntity) playCountDao.deleteSongInPlayCount(playCountEntity)
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> = override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
playCountDao.checkSongExistInPlayCount(songId) playCountDao.checkSongExistInPlayCount(songId)
override suspend fun playCountSongs(): List<PlayCountEntity> = override suspend fun playCountSongs(): List<PlayCountEntity> =

View File

@ -17,9 +17,14 @@ package code.name.monkey.retromusic.repository
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio
import android.provider.MediaStore.Audio.*
import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.Constants.IS_MUSIC
import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.extensions.getInt
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.extensions.getStringOrNull
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.providers.BlacklistStore import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -40,7 +45,7 @@ interface SongRepository {
fun song(cursor: Cursor?): Song fun song(cursor: Cursor?): Song
fun song(songId: Int): Song fun song(songId: Long): Song
} }
class RealSongRepository(private val context: Context) : SongRepository { class RealSongRepository(private val context: Context) : SongRepository {
@ -74,14 +79,14 @@ class RealSongRepository(private val context: Context) : SongRepository {
return songs(makeSongCursor(AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%"))) return songs(makeSongCursor(AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%")))
} }
override fun song(songId: Int): Song { override fun song(songId: Long): Song {
return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString()))) return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString())))
} }
override fun songsByFilePath(filePath: String): List<Song> { override fun songsByFilePath(filePath: String): List<Song> {
return songs( return songs(
makeSongCursor( makeSongCursor(
MediaStore.Audio.AudioColumns.DATA + "=?", AudioColumns.DATA + "=?",
arrayOf(filePath) arrayOf(filePath)
) )
) )
@ -90,19 +95,19 @@ class RealSongRepository(private val context: Context) : SongRepository {
private fun getSongFromCursorImpl( private fun getSongFromCursorImpl(
cursor: Cursor cursor: Cursor
): Song { ): Song {
val id = cursor.getInt(0) val id = cursor.getLong(AudioColumns._ID)
val title = cursor.getString(1) val title = cursor.getString(AudioColumns.TITLE)
val trackNumber = cursor.getInt(2) val trackNumber = cursor.getInt(AudioColumns.TRACK)
val year = cursor.getInt(3) val year = cursor.getInt(AudioColumns.YEAR)
val duration = cursor.getLong(4) val duration = cursor.getLong(AudioColumns.DURATION)
val data = cursor.getString(5) val data = cursor.getString(AudioColumns.DATA)
val dateModified = cursor.getLong(6) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
val albumId = cursor.getInt(7) val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
val albumName = cursor.getString(8) val albumName = cursor.getStringOrNull(AudioColumns.ALBUM)
val artistId = cursor.getInt(9) val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
val artistName = cursor.getString(10) val artistName = cursor.getStringOrNull(AudioColumns.ARTIST)
val composer = cursor.getString(11) val composer = cursor.getStringOrNull(AudioColumns.COMPOSER)
val albumArtist = cursor.getString(12) val albumArtist = cursor.getStringOrNull("album_artist")
return Song( return Song(
id, id,
title, title,
@ -142,10 +147,10 @@ class RealSongRepository(private val context: Context) : SongRepository {
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths) selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
} }
selectionFinal = selectionFinal =
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
try { try {
return context.contentResolver.query( return context.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Media.EXTERNAL_CONTENT_URI,
baseProjection, baseProjection,
selectionFinal, selectionFinal,
selectionValuesFinal, selectionValuesFinal,

View File

@ -90,7 +90,7 @@ class MediaSessionCallback(
} }
} }
private fun checkAndStartPlaying(songs: ArrayList<Song>, itemId: Int) { private fun checkAndStartPlaying(songs: ArrayList<Song>, itemId: Long) {
var songIndex = MusicUtil.indexOfSongInList(songs, itemId) var songIndex = MusicUtil.indexOfSongInList(songs, itemId)
if (songIndex == -1) { if (songIndex == -1) {
songIndex = 0 songIndex = 0

View File

@ -618,7 +618,7 @@ public class MusicService extends Service implements
break; break;
case SHUFFLE_MODE_NONE: case SHUFFLE_MODE_NONE:
this.shuffleMode = shuffleMode; this.shuffleMode = shuffleMode;
int currentSongId = Objects.requireNonNull(getCurrentSong()).getId(); long currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
playingQueue = new ArrayList<>(originalPlayingQueue); playingQueue = new ArrayList<>(originalPlayingQueue);
int newPosition = 0; int newPosition = 0;
if (getPlayingQueue() != null) { if (getPlayingQueue() != null) {

View File

@ -34,7 +34,7 @@ public class AutoGeneratedPlaylistBitmap {
if (songPlaylist == null) return null; if (songPlaylist == null) return null;
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
// lấy toàn bộ album id, loại bỏ trùng nhau // lấy toàn bộ album id, loại bỏ trùng nhau
ArrayList<Integer> albumID = new ArrayList<>(); List<Long> albumID = new ArrayList<>();
for (Song song : songPlaylist) { for (Song song : songPlaylist) {
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId()); if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
} }
@ -42,8 +42,8 @@ public class AutoGeneratedPlaylistBitmap {
long start2 = System.currentTimeMillis() - start; long start2 = System.currentTimeMillis() - start;
// lấy toàn bộ art tồn tại // lấy toàn bộ art tồn tại
ArrayList<Bitmap> art = new ArrayList<Bitmap>(); List<Bitmap> art = new ArrayList<Bitmap>();
for (Integer id : albumID) { for (Long id : albumID) {
Bitmap bitmap = getBitmapWithAlbumId(context, id); Bitmap bitmap = getBitmapWithAlbumId(context, id);
if (bitmap != null) art.add(bitmap); if (bitmap != null) art.add(bitmap);
if (art.size() == 6) break; if (art.size() == 6) break;
@ -168,7 +168,7 @@ public class AutoGeneratedPlaylistBitmap {
else return bitmap; else return bitmap;
} }
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Integer id) { private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
try { try {
return Glide.with(context) return Glide.with(context)
.load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id)) .load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id))

View File

@ -16,6 +16,7 @@ import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
@ -85,7 +86,7 @@ object MusicUtil : KoinComponent {
return albumArtDir return albumArtDir
} }
fun deleteAlbumArt(context: Context, albumId: Int) { fun deleteAlbumArt(context: Context, albumId: Long) {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
val localUri = Uri.parse("content://media/external/audio/albumart") val localUri = Uri.parse("content://media/external/audio/albumart")
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null) contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null)
@ -175,10 +176,9 @@ object MusicUtil : KoinComponent {
return lyrics return lyrics
} }
fun getMediaStoreAlbumCoverUri(albumId: Int): Uri { fun getMediaStoreAlbumCoverUri(albumId: Long): Uri {
val sArtworkUri = val sArtworkUri = Uri.parse("content://media/external/audio/albumart")
Uri.parse("content://media/external/audio/albumart") return ContentUris.withAppendedId(sArtworkUri, albumId)
return ContentUris.withAppendedId(sArtworkUri, albumId.toLong())
} }
@ -249,7 +249,7 @@ object MusicUtil : KoinComponent {
return "$songCount $songString" return "$songCount $songString"
} }
fun getSongFileUri(songId: Int): Uri { fun getSongFileUri(songId: Long): Uri {
return ContentUris.withAppendedId( return ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
songId.toLong() songId.toLong()
@ -268,18 +268,13 @@ object MusicUtil : KoinComponent {
return if (year > 0) year.toString() else "-" return if (year > 0) year.toString() else "-"
} }
fun indexOfSongInList(songs: List<Song>, songId: Int): Int { fun indexOfSongInList(songs: List<Song>, songId: Long): Int {
for (i in songs.indices) { return songs.indexOfFirst { it.id == songId }
if (songs[i].id == songId) {
return i
}
}
return -1
} }
fun insertAlbumArt( fun insertAlbumArt(
context: Context, context: Context,
albumId: Int, albumId: Long,
path: String? path: String?
) { ) {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
@ -306,7 +301,7 @@ object MusicUtil : KoinComponent {
fun isFavorite(context: Context, song: Song): Boolean { fun isFavorite(context: Context, song: Song): Boolean {
return PlaylistsUtil return PlaylistsUtil
.doPlaylistContains(context, getFavoritesPlaylist(context).id.toLong(), song.id) .doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id)
} }
fun isFavoritePlaylist( fun isFavoritePlaylist(
@ -387,7 +382,7 @@ object MusicUtil : KoinComponent {
// as from the album art cache // as from the album art cache
cursor.moveToFirst() cursor.moveToFirst()
while (!cursor.isAfterLast) { while (!cursor.isAfterLast) {
val id = cursor.getInt(0) val id = cursor.getLong(BaseColumns._ID)
val song: Song = songRepository.song(id) val song: Song = songRepository.song(id)
removeFromQueue(song) removeFromQueue(song)
cursor.moveToNext() cursor.moveToNext()
@ -452,7 +447,7 @@ object MusicUtil : KoinComponent {
// as from the album art cache // as from the album art cache
cursor.moveToFirst() cursor.moveToFirst()
while (!cursor.isAfterLast) { while (!cursor.isAfterLast) {
val id: Int = cursor.getInt(0) val id = cursor.getLong(BaseColumns._ID)
val song: Song = RealSongRepository(context).song(id) val song: Song = RealSongRepository(context).song(id)
removeFromQueue(song) removeFromQueue(song)
cursor.moveToNext() cursor.moveToNext()

View File

@ -43,7 +43,7 @@ import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
public class PlaylistsUtil { public class PlaylistsUtil {
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) { public static long createPlaylist(@NonNull final Context context, @Nullable final String name) {
int id = -1; int id = -1;
if (name != null && name.length() > 0) { if (name != null && name.length() > 0) {
try { try {
@ -101,13 +101,13 @@ public class PlaylistsUtil {
} }
} }
public static void addToPlaylist(@NonNull final Context context, final Song song, final int playlistId, final boolean showToastOnFinish) { public static void addToPlaylist(@NonNull final Context context, final Song song, final long playlistId, final boolean showToastOnFinish) {
List<Song> helperList = new ArrayList<>(); List<Song> helperList = new ArrayList<>();
helperList.add(song); helperList.add(song);
addToPlaylist(context, helperList, playlistId, showToastOnFinish); addToPlaylist(context, helperList, playlistId, showToastOnFinish);
} }
public static void addToPlaylist(@NonNull final Context context, @NonNull final List<Song> songs, final int playlistId, final boolean showToastOnFinish) { public static void addToPlaylist(@NonNull final Context context, @NonNull final List<Song> songs, final long playlistId, final boolean showToastOnFinish) {
final int size = songs.size(); final int size = songs.size();
final ContentResolver resolver = context.getContentResolver(); final ContentResolver resolver = context.getContentResolver();
final String[] projection = new String[]{ final String[] projection = new String[]{
@ -180,7 +180,7 @@ public class PlaylistsUtil {
return ""; return "";
} }
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) { public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, long playlistId) {
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
"external", playlistId); "external", playlistId);
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?"; String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
@ -193,7 +193,7 @@ public class PlaylistsUtil {
} }
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) { public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
final int playlistId = songs.get(0).getPlaylistId(); final long playlistId = songs.get(0).getPlaylistId();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
"external", playlistId); "external", playlistId);
String[] selectionArgs = new String[songs.size()]; String[] selectionArgs = new String[songs.size()];
@ -211,7 +211,7 @@ public class PlaylistsUtil {
} }
} }
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) { public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final long songId) {
if (playlistId != -1) { if (playlistId != -1) {
try { try {
Cursor c = context.getContentResolver().query( Cursor c = context.getContentResolver().query(
@ -229,7 +229,7 @@ public class PlaylistsUtil {
return false; return false;
} }
public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) { public static boolean moveItem(@NonNull final Context context, long playlistId, int from, int to) {
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(), return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
playlistId, from, to); playlistId, from, to);
} }

View File

@ -32,7 +32,7 @@
tools:layout="@layout/fragment_album_details"> tools:layout="@layout/fragment_album_details">
<argument <argument
android:name="extra_album_id" android:name="extra_album_id"
app:argType="integer" /> app:argType="long" />
</fragment> </fragment>
<fragment <fragment
@ -42,7 +42,7 @@
tools:layout="@layout/fragment_artist_details"> tools:layout="@layout/fragment_artist_details">
<argument <argument
android:name="extra_artist_id" android:name="extra_artist_id"
app:argType="integer" /> app:argType="long" />
</fragment> </fragment>
<fragment <fragment