diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index c7296dda..3e068f20 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -162,14 +162,14 @@ private val viewModules = module { LibraryViewModel(get()) } - viewModel { (albumId: Int) -> + viewModel { (albumId: Long) -> AlbumDetailsViewModel( get(), albumId ) } - viewModel { (artistId: Int) -> + viewModel { (artistId: Long) -> ArtistDetailsViewModel( get(), artistId diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 517c8254..6eb4cc73 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -97,8 +97,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis MusicPlayerRemote.playFromUri(uri) handled = true } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) { - val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt() - if (id >= 0) { + val id = parseLongFromIntent(intent, "playlistId", "playlist") + if (id >= 0L) { val position: Int = intent.getIntExtra("position", 0) val songs: List = PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id) @@ -106,19 +106,19 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis handled = true } } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) { - val id = parseIdFromIntent(intent, "albumId", "album").toInt() - if (id >= 0) { + val id = parseLongFromIntent(intent, "albumId", "album") + if (id >= 0L) { val position: Int = intent.getIntExtra("position", 0) MusicPlayerRemote.openQueue( - libraryViewModel.albumById(id).songs!!, + libraryViewModel.albumById(id).songs, position, true ) handled = true } } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { - val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt() - if (id >= 0) { + val id = parseLongFromIntent(intent, "artistId", "artist") + if (id >= 0L) { val position: Int = intent.getIntExtra("position", 0) MusicPlayerRemote.openQueue( libraryViewModel.artistById(id).songs, @@ -135,7 +135,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis } - private fun parseIdFromIntent( + private fun parseLongFromIntent( intent: Intent, longKey: String, stringKey: String ): Long { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt index 1571e07a..7bb8a49c 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt @@ -40,7 +40,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { val repository by inject() lateinit var saveFab: MaterialButton - protected var id: Int = 0 + protected var id: Long = 0 private set private var paletteColorPrimary: Int = 0 private var isInNoImageMode: Boolean = false @@ -251,7 +251,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { private fun getIntentExtras() { val intentExtras = intent.extras 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 8a908dd6..a54633fa 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -18,6 +18,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder 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.RetroColorUtil.generatePalette import code.name.monkey.retromusic.util.RetroColorUtil.getColor @@ -168,12 +169,8 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher { } override fun getSongPaths(): List { - val songs = repository.albumById(id).songs - val paths = ArrayList(songs!!.size) - for (song in songs) { - paths.add(song.data) - } - return paths + return repository.albumById(id).songs + .map(Song::data) } override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java index 58d6ce75..f079b318 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java @@ -71,13 +71,13 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter { - if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) { - categoryInfo.visible = !categoryInfo.visible; - holder.checkBox.setChecked(categoryInfo.visible); + if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) { + categoryInfo.setVisible(!categoryInfo.isVisible()); + holder.checkBox.setChecked(categoryInfo.isVisible()); } else { Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, Toast.LENGTH_SHORT).show(); @@ -110,9 +110,9 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter + fun checkSongExistInPlayCount(songId: Long): List @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") fun playCountSongs(): List @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") - fun updateQuantity(id: Int) + fun updateQuantity(id: Long) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountEntity.kt index 94d496d4..0fe6c088 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountEntity.kt @@ -7,7 +7,7 @@ import androidx.room.PrimaryKey @Entity class PlayCountEntity( @PrimaryKey - val id: Int, + val id: Long, val title: String, @ColumnInfo(name = "track_number") val trackNumber: Int, @@ -17,11 +17,11 @@ class PlayCountEntity( @ColumnInfo(name = "date_modified") val dateModified: Long, @ColumnInfo(name = "album_id") - val albumId: Int, + val albumId: Long, @ColumnInfo(name = "album_name") val albumName: String, @ColumnInfo(name = "artist_id") - val artistId: Int, + val artistId: Long, @ColumnInfo(name = "artist_name") val artistName: String, val composer: String?, diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 219ca590..36a4e833 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -9,7 +9,7 @@ interface PlaylistDao { suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long @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") fun isPlaylistExists(name: String): List @@ -18,10 +18,10 @@ interface PlaylistDao { suspend fun playlists(): List @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") - suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int) + suspend fun deleteSongFromPlaylist(playlistId: Long, songId: Long) @Transaction @Query("SELECT * FROM PlaylistEntity") @@ -31,10 +31,10 @@ interface PlaylistDao { suspend fun insertSongsToPlaylist(songEntities: List) @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId") - suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List + suspend fun isSongExistsInPlaylist(playlistId: Long, songId: Long): List @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId") - fun songsFromPlaylist(playlistId: Int): LiveData> + fun songsFromPlaylist(playlistId: Long): LiveData> @Delete suspend fun deletePlaylist(playlistEntity: PlaylistEntity) @@ -47,10 +47,10 @@ interface PlaylistDao { @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") - fun favoritesSongsLiveData(playlistId: Int): LiveData> + fun favoritesSongsLiveData(playlistId: Long): LiveData> @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") - fun favoritesSongs(playlistId: Int): List + fun favoritesSongs(playlistId: Long): List } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt index 3bb1681f..236e9cb4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt @@ -9,10 +9,9 @@ import kotlinx.android.parcel.Parcelize @Entity @Parcelize class PlaylistEntity( - @ColumnInfo(name = "playlist_name") - val playlistName: String -) : Parcelable { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "playlist_id") - var playListId: Int = 0 -} \ No newline at end of file + val playListId: Long = 0, + @ColumnInfo(name = "playlist_name") + val playlistName: String +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index 19a50fe0..6a6d236a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -10,9 +10,12 @@ import kotlinx.android.parcel.Parcelize @Parcelize @Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)]) class SongEntity( + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "song_key") + val songPrimaryKey: Long = 0L, @ColumnInfo(name = "playlist_creator_id") - val playlistCreatorId: Int, - val id: Int, + val playlistCreatorId: Long, + val id: Long, val title: String, @ColumnInfo(name = "track_number") val trackNumber: Int, @@ -22,19 +25,15 @@ class SongEntity( @ColumnInfo(name = "date_modified") val dateModified: Long, @ColumnInfo(name = "album_id") - val albumId: Int, + val albumId: Long, @ColumnInfo(name = "album_name") val albumName: String, @ColumnInfo(name = "artist_id") - val artistId: Int, + val artistId: Long, @ColumnInfo(name = "artist_name") val artistName: String, val composer: String?, @ColumnInfo(name = "album_artist") val albumArtist: String? -) : Parcelable { - @PrimaryKey(autoGenerate = true) - @ColumnInfo(name = "song_key") - var songPrimaryKey: Long = 0 -} +) : Parcelable diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt index d5f009e0..fd7c116a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt @@ -8,7 +8,7 @@ fun List.toSongs(): List { } } -fun List.toSongs(playlistId: Int): List { +fun List.toSongs(playlistId: Long): List { return map { it.toSongEntity(playlistId) } @@ -16,75 +16,75 @@ fun List.toSongs(playlistId: Int): List { fun SongEntity.toSong(): Song { return Song( - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist + 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 ) } fun PlayCountEntity.toSong(): Song { return Song( - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist + 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 ) } fun HistoryEntity.toSong(): Song { return Song( - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist + 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 ) } fun Song.toPlayCount(): PlayCountEntity { return PlayCountEntity( - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist, - System.currentTimeMillis(), - 1 + 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, + timePlayed = System.currentTimeMillis(), + playCount = 1 ) } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt index db5158ae..b1ceb033 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -56,8 +56,8 @@ class CreatePlaylistDialog : DialogFragment() { lifecycleScope.launch(Dispatchers.IO) { if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) { val playlistId: Long = - libraryViewModel.createPlaylist(PlaylistEntity(playlistName)) - libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) + libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlistName)) + libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) }) libraryViewModel.forceReload(Playlists) } else { Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt new file mode 100644 index 00000000..22c8e866 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt index 6c7230a5..fc9ee92c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt @@ -178,11 +178,11 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de 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) { } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 3999ee70..4a890613 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -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) } @@ -193,8 +193,8 @@ class LibraryViewModel( repository.deleteRoomPlaylist(playlists) } - suspend fun albumById(id: Int) = repository.albumById(id) - suspend fun artistById(id: Int) = repository.artistById(id) + suspend fun albumById(id: Long) = repository.albumById(id) + suspend fun artistById(id: Long) = repository.artistById(id) suspend fun favoritePlaylist() = repository.favoritePlaylist() suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song) suspend fun insertSongs(songs: List) = repository.insertSongs(songs) @@ -217,9 +217,9 @@ class LibraryViewModel( } repository.insertSongs(songEntities) } else { - val playListId = createPlaylist(PlaylistEntity(playlist.name)) + val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name)) val songEntities = playlist.getSongs().map { - it.toSongEntity(playListId.toInt()) + it.toSongEntity(playListId) } repository.insertSongs(songEntities) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index bade59ff..0001ee8c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -254,7 +254,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det playAction.applyOutlineColor(color) } - override fun onAlbumClick(albumId: Int, view: View) { + override fun onAlbumClick(albumId: Long, view: View) { findNavController().navigate( R.id.albumDetailsFragment, bundleOf(EXTRA_ALBUM_ID to albumId) @@ -349,29 +349,31 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det private fun setSaveSortOrder(sortOrder: String) { PreferenceUtil.albumDetailSongSortOrder = sortOrder - when (sortOrder) { - SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 -> + val songs = when (sortOrder) { + SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 -> o1.trackNumber.compareTo( 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( 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( o1.title ) - }) - SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 -> + } + SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 -> o1.duration.compareTo( o2.duration ) - }) + } + else -> throw IllegalArgumentException("invalid $sortOrder") } - album.songs?.let { simpleSongAdapter.swapDataSet(it) } + album = album.copy(songs = songs) + simpleSongAdapter.swapDataSet(album.songs) } companion object { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt index 0cb4860a..02544933 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt @@ -13,14 +13,14 @@ import kotlinx.coroutines.Dispatchers.IO class AlbumDetailsViewModel( private val repository: RealRepository, - private val albumId: Int + private val albumId: Long ) : ViewModel(), MusicServiceEventListener { fun getAlbum(): LiveData = liveData(IO) { emit(repository.albumByIdAsync(albumId)) } - fun getArtist(artistId: Int): LiveData = liveData(IO) { + fun getArtist(artistId: Long): LiveData = liveData(IO) { val artist = repository.artistById(artistId) emit(artist) } @@ -31,7 +31,7 @@ class AlbumDetailsViewModel( } fun getMoreAlbums(artist: Artist): LiveData> = 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) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index 9f7b7ce0..8da03090 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -97,7 +97,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment = liveData(IO) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt index b39909d3..5ab722b0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt @@ -96,7 +96,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Album.kt b/app/src/main/java/code/name/monkey/retromusic/model/Album.kt index 477dba87..d4369b33 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Album.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Album.kt @@ -14,19 +14,15 @@ package code.name.monkey.retromusic.model -import java.util.* - -class Album { - - val songs: ArrayList? - - val id: Int - get() = safeGetFirstSong().albumId +data class Album( + val id: Long, + val songs: List +) { val title: String? get() = safeGetFirstSong().albumName - val artistId: Int + val artistId: Long get() = safeGetFirstSong().artistId val artistName: String? @@ -39,20 +35,17 @@ class Album { get() = safeGetFirstSong().dateModified val songCount: Int - get() = songs!!.size + get() = songs.size val albumArtist: String? get() = safeGetFirstSong().albumArtist - constructor(songs: ArrayList) { - this.songs = songs - } - - constructor() { - this.songs = ArrayList() - } - fun safeGetFirstSong(): Song { - return if (songs!!.isEmpty()) Song.emptySong else songs[0] + return songs.firstOrNull() ?: Song.emptySong } + + companion object { + val empty = Album(-1, emptyList()) + } + } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Artist.kt b/app/src/main/java/code/name/monkey/retromusic/model/Artist.kt index 3abba61d..98fe4209 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Artist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Artist.kt @@ -17,11 +17,10 @@ package code.name.monkey.retromusic.model import code.name.monkey.retromusic.util.MusicUtil import java.util.* -class Artist { - val albums: ArrayList? - - val id: Int - get() = safeGetFirstAlbum().artistId +data class Artist( + val id: Long, + val albums: List +) { val name: String get() { @@ -34,37 +33,25 @@ class Artist { val songCount: Int get() { var songCount = 0 - for (album in albums!!) { + for (album in albums) { songCount += album.songCount } return songCount } val albumCount: Int - get() = albums!!.size + get() = albums.size - val songs: ArrayList - get() { - val songs = ArrayList() - for (album in albums!!) { - songs.addAll(album.songs!!) - } - return songs - } - - constructor(albums: ArrayList) { - this.albums = albums - } - - constructor() { - this.albums = ArrayList() - } + val songs: List + get() = albums.flatMap { it.songs } fun safeGetFirstAlbum(): Album { - return if (albums!!.isEmpty()) Album() else albums[0] + return albums.firstOrNull() ?: Album.empty } companion object { const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist" + val empty = Artist(-1, emptyList()) + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java deleted file mode 100644 index 5b206ba2..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java +++ /dev/null @@ -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 CREATOR = new Creator() { - 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; - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.kt b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.kt new file mode 100644 index 00000000..978c2fe1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.kt @@ -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); + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Contributor.kt b/app/src/main/java/code/name/monkey/retromusic/model/Contributor.kt index 519e63c1..6ea869f3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Contributor.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Contributor.kt @@ -16,8 +16,10 @@ package code.name.monkey.retromusic.model import com.google.gson.annotations.SerializedName -class Contributor( +data class Contributor( val name: String, val summary: String, - val link: String, @SerializedName("profile_image") val profileImage: String + val link: String, + @SerializedName("profile_image") + val profileImage: String ) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt b/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt index c2a7e274..961f2ba1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt @@ -18,4 +18,8 @@ import android.os.Parcelable import kotlinx.android.parcel.Parcelize @Parcelize -data class Genre(val id: Int = -1, val name: String, val songCount: Int) : Parcelable \ No newline at end of file +data class Genre( + val id: Long, + val name: String, + val songCount: Int +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Home.kt b/app/src/main/java/code/name/monkey/retromusic/model/Home.kt index 2224417f..9a12344f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Home.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Home.kt @@ -17,7 +17,7 @@ package code.name.monkey.retromusic.model import androidx.annotation.StringRes import code.name.monkey.retromusic.HomeSection -class Home( +data class Home( val arrayList: List, @HomeSection val homeSection: Int, diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Playlist.kt b/app/src/main/java/code/name/monkey/retromusic/model/Playlist.kt index e18d4971..690f753b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Playlist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Playlist.kt @@ -10,10 +10,14 @@ import org.koin.core.get @Parcelize open class Playlist( - val id: Int = -1, - val name: String = "" + val id: Long, + val name: String ) : Parcelable, KoinComponent { + companion object { + val empty = Playlist(-1, "") + } + // this default implementation covers static playlists fun getSongs(): List { 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 + } + + } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java b/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java deleted file mode 100644 index a2b556f5..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.java +++ /dev/null @@ -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; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.kt b/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.kt new file mode 100644 index 00000000..8b7cbc00 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/PlaylistSong.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt index 0fe59d8c..35bf1bfa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt @@ -18,78 +18,120 @@ import code.name.monkey.retromusic.db.HistoryEntity import code.name.monkey.retromusic.db.SongEntity import kotlinx.android.parcel.Parcelize +// update equals and hashcode if fields changes @Parcelize open class Song( - val id: Int, - val title: String, - val trackNumber: Int, - val year: Int, - val duration: Long, - val data: String, - val dateModified: Long, - val albumId: Int, - val albumName: String, - val artistId: Int, - val artistName: String, - val composer: String?, - val albumArtist: String? + open val id: Long, + open val title: String, + open val trackNumber: Int, + open val year: Int, + open val duration: Long, + open val data: String, + open val dateModified: Long, + open val albumId: Long, + open val albumName: String, + open val artistId: Long, + open val artistName: String, + open val composer: String?, + open val albumArtist: String? ) : Parcelable { fun toHistoryEntity(timePlayed: Long): HistoryEntity { return HistoryEntity( - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist, - timePlayed + 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, + timePlayed = timePlayed ) } - fun toSongEntity(playListId: Int): SongEntity { + fun toSongEntity(playListId: Long): SongEntity { return SongEntity( - playListId, - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist + playlistCreatorId = playListId, + 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 ) } + // 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 { @JvmStatic val emptySong = Song( - -1, - "", - -1, - -1, - -1, - "", - -1, - -1, - "", - -1, - "", - "", - "" + id = -1, + title = "", + trackNumber = -1, + year = -1, + duration = -1, + data = "", + dateModified = -1, + albumId = -1, + albumName = "", + artistId = -1, + artistName = "", + composer = "", + albumArtist = "" ) } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.kt index 93cc2ccf..8098f2c0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/AbsSmartPlaylist.kt @@ -5,6 +5,9 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.model.AbsCustomPlaylist abstract class AbsSmartPlaylist( - name: String = "", + name: String, @DrawableRes val iconRes: Int = R.drawable.ic_queue_music -) : AbsCustomPlaylist(-Math.abs(31 * name.hashCode() + iconRes * name.hashCode() * 31 * 31), name) \ No newline at end of file +) : AbsCustomPlaylist( + id = PlaylistIdGenerator(name, iconRes), + name = name +) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.kt index 4653ca5f..f9152967 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/HistoryPlaylist.kt @@ -7,12 +7,11 @@ import kotlinx.android.parcel.Parcelize import org.koin.core.KoinComponent @Parcelize -class HistoryPlaylist : - AbsSmartPlaylist( - App.getContext().getString(R.string.history), - R.drawable.ic_history - ), - KoinComponent { +class HistoryPlaylist : AbsSmartPlaylist( + name = App.getContext().getString(R.string.history), + iconRes = R.drawable.ic_history +), KoinComponent { + override fun songs(): List { return topPlayedRepository.recentlyPlayedTracks() } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.kt index 43048e7d..6b8dafd4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/LastAddedPlaylist.kt @@ -6,8 +6,10 @@ import code.name.monkey.retromusic.model.Song import kotlinx.android.parcel.Parcelize @Parcelize -class LastAddedPlaylist : - AbsSmartPlaylist(App.getContext().getString(R.string.last_added), R.drawable.ic_library_add) { +class LastAddedPlaylist : AbsSmartPlaylist( + name = App.getContext().getString(R.string.last_added), + iconRes = R.drawable.ic_library_add +) { override fun songs(): List { return lastAddedRepository.recentSongs() } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/NotPlayedPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/NotPlayedPlaylist.kt index 760f2c99..d9cbd6af 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/NotPlayedPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/NotPlayedPlaylist.kt @@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize @Parcelize class NotPlayedPlaylist : AbsSmartPlaylist( - App.getContext().getString(R.string.not_recently_played), - R.drawable.ic_watch_later + name = App.getContext().getString(R.string.not_recently_played), + iconRes = R.drawable.ic_watch_later ) { override fun songs(): List { return topPlayedRepository.notRecentlyPlayedTracks() diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/PlaylistIdGenerator.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/PlaylistIdGenerator.kt new file mode 100644 index 00000000..f81ceb6c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/PlaylistIdGenerator.kt @@ -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) + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.kt index 8ba44e5c..69372abe 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/ShuffleAllPlaylist.kt @@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize @Parcelize class ShuffleAllPlaylist : AbsSmartPlaylist( - App.getContext().getString(R.string.action_shuffle_all), - R.drawable.ic_shuffle + name = App.getContext().getString(R.string.action_shuffle_all), + iconRes = R.drawable.ic_shuffle ) { override fun songs(): List { return songRepository.songs() diff --git a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/TopTracksPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/TopTracksPlaylist.kt index b66b3f5a..4348ce82 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/TopTracksPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/smartplaylist/TopTracksPlaylist.kt @@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize @Parcelize class TopTracksPlaylist : AbsSmartPlaylist( - App.getContext().getString(R.string.my_top_tracks), - R.drawable.ic_trending_up + name = App.getContext().getString(R.string.my_top_tracks), + iconRes = R.drawable.ic_trending_up ) { override fun songs(): List { return topPlayedRepository.topTracks() diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/AlbumRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/AlbumRepository.kt index 5fd9e6f7..97b8206a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/AlbumRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/AlbumRepository.kt @@ -31,7 +31,7 @@ interface AlbumRepository { fun albums(query: String): List - fun album(albumId: Int): Album + fun album(albumId: Long): Album } class RealAlbumRepository(private val songRepository: RealSongRepository) : @@ -59,70 +59,42 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) : return splitIntoAlbums(songs) } - override fun album(albumId: Int): Album { + override fun album(albumId: Long): Album { val cursor = songRepository.makeSongCursor( AudioColumns.ALBUM_ID + "=?", arrayOf(albumId.toString()), getSongLoaderSortOrder() ) val songs = songRepository.songs(cursor) - val album = Album(ArrayList(songs)) + val album = Album(albumId, songs) sortAlbumSongs(album) return album } fun splitIntoAlbums( - songs: List? + songs: List ): List { - val albums = ArrayList() - if (songs != null) { - for (song in songs) { - getOrCreateAlbum(albums, song.albumId).songs?.add(song) - } - } - for (album in albums) { - sortAlbumSongs(album) - } - return albums + return songs.groupBy { it.albumId } + .map { sortAlbumSongs(Album(it.key, it.value)) } } - private fun getOrCreateAlbum( - albums: ArrayList, - albumId: Int - ): Album { - for (album in albums) { - if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) { - return album + private fun sortAlbumSongs(album: Album): Album { + val songs = when (PreferenceUtil.albumDetailSongSortOrder) { + SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 -> + o1.trackNumber.compareTo(o2.trackNumber) } + SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 -> + o1.title.compareTo(o2.title) + } + SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 -> + o2.title.compareTo(o1.title) + } + SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 -> + o1.duration.compareTo(o2.duration) + } + else -> throw IllegalArgumentException("invalid ${PreferenceUtil.albumDetailSongSortOrder}") } - val album = Album() - albums.add(album) - return album - } - - private fun sortAlbumSongs(album: Album) { - 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 - ) - }) - } + return album.copy(songs = songs) } private fun getSongLoaderSortOrder(): String { diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/ArtistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/ArtistRepository.kt index 9a309b2a..9c14becf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/ArtistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/ArtistRepository.kt @@ -26,7 +26,7 @@ interface ArtistRepository { fun artists(query: String): List - fun artist(artistId: Int): Artist + fun artist(artistId: Long): Artist } class RealArtistRepository( @@ -73,20 +73,18 @@ class RealArtistRepository( } private fun splitIntoAlbumArtists(albums: List): List { - // First group the songs in albums by filtering each artist name - val amap = hashMapOf() - albums.forEach { - val key = it.albumArtist - if (key != null) { - val artist: Artist = if (amap[key] != null) amap[key]!! else Artist() - artist.albums?.add(it) - amap[key] = artist + return albums.groupBy { it.albumArtist } + .map { + val currentAlbums = it.value + if (albums.isNotEmpty()) { + Artist(currentAlbums[0].id, currentAlbums) + } else { + Artist.empty + } } - } - return ArrayList(amap.values) } - override fun artist(artistId: Int): Artist { + override fun artist(artistId: Long): Artist { val songs = songRepository.songs( songRepository.makeSongCursor( AudioColumns.ARTIST_ID + "=?", @@ -94,27 +92,12 @@ class RealArtistRepository( getSongLoaderSortOrder() ) ) - return Artist(ArrayList(albumRepository.splitIntoAlbums(songs))) + return Artist(artistId, albumRepository.splitIntoAlbums(songs)) } - fun splitIntoArtists(albums: List?): List { - val artists = mutableListOf() - if (albums != null) { - for (album in albums) { - getOrCreateArtist(artists, album.artistId).albums!!.add(album) - } - } - return artists + fun splitIntoArtists(albums: List): List { + return albums.groupBy { it.artistId } + .map { Artist(it.key, it.value) } } - private fun getOrCreateArtist(artists: MutableList, 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 - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt index ff7f3f5e..34ce1980 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt @@ -22,6 +22,8 @@ import android.provider.MediaStore import android.provider.MediaStore.Audio.Genres import code.name.monkey.retromusic.Constants.IS_MUSIC 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.Song import code.name.monkey.retromusic.util.PreferenceUtil @@ -29,7 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil interface GenreRepository { fun genres(): List - fun songs(genreId: Int): List + fun songs(genreId: Long): List } class RealGenreRepository( @@ -41,25 +43,25 @@ class RealGenreRepository( return getGenresFromCursor(makeGenreCursor()) } - override fun songs(genreId: Int): List { + override fun songs(genreId: Long): List { // The genres table only stores songs that have a genre specified, // so we need to get songs without a genre a different way. - return if (genreId == -1) { + return if (genreId == -1L) { getSongsWithNoGenre() } else songRepository.songs(makeGenreSongCursor(genreId)) } private fun getGenreFromCursor(cursor: Cursor): Genre { - val id = cursor.getInt(0) - val name = cursor.getString(1) + val id = cursor.getLong(Genres._ID) + val name = cursor.getString(Genres.NAME) val songCount = songs(id).size return Genre(id, name, songCount) } private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre { - val id = cursor.getInt(0) - val name = cursor.getString(1) + val id = cursor.getLong(Genres._ID) + val name = cursor.getString(Genres.NAME) 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( - Genres.Members.getContentUri("external", genreId.toLong()), + Genres.Members.getContentUri("external", genreId), baseProjection, IS_MUSIC, null, diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt index 3462df9d..79ad8ca7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt @@ -18,8 +18,13 @@ import android.content.ContentResolver import android.database.Cursor import android.provider.BaseColumns 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.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.PlaylistSong import code.name.monkey.retromusic.model.Song @@ -40,11 +45,11 @@ interface PlaylistRepository { fun favoritePlaylist(playlistName: String): List - fun deletePlaylist(playlistId: Int) + fun deletePlaylist(playlistId: Long) - fun playlist(playlistId: Int): Playlist + fun playlist(playlistId: Long): Playlist - fun playlistSongs(playlistId: Int): List + fun playlistSongs(playlistId: Long): List } class RealPlaylistRepository( @@ -52,19 +57,20 @@ class RealPlaylistRepository( ) : PlaylistRepository { override fun playlist(cursor: Cursor?): Playlist { - var playlist = Playlist() - if (cursor != null && cursor.moveToFirst()) { - playlist = getPlaylistFromCursorImpl(cursor) + return cursor.use { + if (cursor?.moveToFirst() == true) { + getPlaylistFromCursorImpl(cursor) + } else { + Playlist.empty + } } - cursor?.close() - return playlist } override fun playlist(playlistName: String): Playlist { return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName))) } - override fun playlist(playlistId: Int): Playlist { + override fun playlist(playlistId: Long): Playlist { return playlist( makePlaylistCursor( BaseColumns._ID + "=?", @@ -101,8 +107,8 @@ class RealPlaylistRepository( ) } - override fun deletePlaylist(playlistId: Int) { - val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI + override fun deletePlaylist(playlistId: Long) { + val localUri = EXTERNAL_CONTENT_URI val localStringBuilder = StringBuilder() localStringBuilder.append("_id IN (") localStringBuilder.append(playlistId) @@ -113,12 +119,12 @@ class RealPlaylistRepository( private fun getPlaylistFromCursorImpl( cursor: Cursor ): Playlist { - val id = cursor.getInt(0) - val name = cursor.getString(1) + val id = cursor.getLong(MediaStore.MediaColumns._ID) + val name = cursor.getString(NAME) return Playlist(id, name) } - override fun playlistSongs(playlistId: Int): List { + override fun playlistSongs(playlistId: Long): List { val songs = arrayListOf() val cursor = makePlaylistSongCursor(playlistId) @@ -131,21 +137,21 @@ class RealPlaylistRepository( return songs } - private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong { - val id = cursor.getInt(0) - val title = cursor.getString(1) - val trackNumber = cursor.getInt(2) - val year = cursor.getInt(3) - val duration = cursor.getLong(4) - val data = cursor.getString(5) - val dateModified = cursor.getLong(6) - val albumId = cursor.getInt(7) - val albumName = cursor.getString(8) - val artistId = cursor.getInt(9) - val artistName = cursor.getString(10) - val idInPlaylist = cursor.getInt(11) - val composer = cursor.getString(12) - val albumArtist = cursor.getString(13) + private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong { + val id = cursor.getLong(Members.AUDIO_ID) + val title = cursor.getString(AudioColumns.TITLE) + val trackNumber = cursor.getInt(AudioColumns.TRACK) + val year = cursor.getInt(AudioColumns.YEAR) + val duration = cursor.getLong(AudioColumns.DURATION) + val data = cursor.getString(AudioColumns.DATA) + val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) + val albumId = cursor.getLong(AudioColumns.ALBUM_ID) + val albumName = cursor.getString(AudioColumns.ALBUM) + val artistId = cursor.getLong(AudioColumns.ARTIST_ID) + val artistName = cursor.getString(AudioColumns.ARTIST) + val idInPlaylist = cursor.getLong(Members._ID) + val composer = cursor.getString(AudioColumns.COMPOSER) + val albumArtist = cursor.getStringOrNull("album_artist") return PlaylistSong( id, title, @@ -170,37 +176,37 @@ class RealPlaylistRepository( values: Array? ): Cursor? { return contentResolver.query( - MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, + EXTERNAL_CONTENT_URI, arrayOf( BaseColumns._ID, /* 0 */ PlaylistsColumns.NAME /* 1 */ ), selection, 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( - MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()), + Members.getContentUri("external", playlistId), arrayOf( - MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0 - MediaStore.Audio.AudioColumns.TITLE, // 1 - MediaStore.Audio.AudioColumns.TRACK, // 2 - MediaStore.Audio.AudioColumns.YEAR, // 3 - MediaStore.Audio.AudioColumns.DURATION, // 4 - MediaStore.Audio.AudioColumns.DATA, // 5 - MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6 - MediaStore.Audio.AudioColumns.ALBUM_ID, // 7 - MediaStore.Audio.AudioColumns.ALBUM, // 8 - MediaStore.Audio.AudioColumns.ARTIST_ID, // 9 - MediaStore.Audio.AudioColumns.ARTIST, // 10 - MediaStore.Audio.Playlists.Members._ID,//11 - MediaStore.Audio.AudioColumns.COMPOSER,//12 + Members.AUDIO_ID, // 0 + AudioColumns.TITLE, // 1 + AudioColumns.TRACK, // 2 + AudioColumns.YEAR, // 3 + AudioColumns.DURATION, // 4 + AudioColumns.DATA, // 5 + AudioColumns.DATE_MODIFIED, // 6 + AudioColumns.ALBUM_ID, // 7 + AudioColumns.ALBUM, // 8 + AudioColumns.ARTIST_ID, // 9 + AudioColumns.ARTIST, // 10 + Members._ID,//11 + AudioColumns.COMPOSER,//12 "album_artist"//13 - ), Constants.IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER + ), Constants.IS_MUSIC, null, Members.DEFAULT_SORT_ORDER ) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt index 96f86d37..fa24d931 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt @@ -18,7 +18,12 @@ import android.content.Context import android.database.Cursor import android.provider.MediaStore 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.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.Playlist import code.name.monkey.retromusic.model.PlaylistSong @@ -42,7 +47,7 @@ object PlaylistSongsLoader { } @JvmStatic - fun getPlaylistSongList(context: Context, playlistId: Int): List { + fun getPlaylistSongList(context: Context, playlistId: Long): List { val songs = mutableListOf() val cursor = makePlaylistSongCursor( @@ -64,21 +69,22 @@ object PlaylistSongsLoader { return songs } - private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong { - val id = cursor.getInt(0) - val title = cursor.getString(1) - val trackNumber = cursor.getInt(2) - val year = cursor.getInt(3) - val duration = cursor.getLong(4) - val data = cursor.getString(5) - val dateModified = cursor.getLong(6) - val albumId = cursor.getInt(7) - val albumName = cursor.getString(8) - val artistId = cursor.getInt(9) - val artistName = cursor.getString(10) - val idInPlaylist = cursor.getInt(11) - val composer = cursor.getString(12) - val albumArtist = cursor.getString(13) + // TODO duplicated in [PlaylistRepository.kt] + private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong { + val id = cursor.getLong(Members.AUDIO_ID) + val title = cursor.getString(AudioColumns.TITLE) + val trackNumber = cursor.getInt(AudioColumns.TRACK) + val year = cursor.getInt(AudioColumns.YEAR) + val duration = cursor.getLong(AudioColumns.DURATION) + val data = cursor.getString(AudioColumns.DATA) + val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) + val albumId = cursor.getLong(AudioColumns.ALBUM_ID) + val albumName = cursor.getString(AudioColumns.ALBUM) + val artistId = cursor.getLong(AudioColumns.ARTIST_ID) + val artistName = cursor.getString(AudioColumns.ARTIST) + val idInPlaylist = cursor.getLong(Members._ID) + val composer = cursor.getString(AudioColumns.COMPOSER) + val albumArtist = cursor.getStringOrNull("album_artist") return PlaylistSong( id, title, @@ -98,12 +104,12 @@ object PlaylistSongsLoader { ) } - private fun makePlaylistSongCursor(context: Context, playlistId: Int): Cursor? { + private fun makePlaylistSongCursor(context: Context, playlistId: Long): Cursor? { try { return context.contentResolver.query( - MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()), + Members.getContentUri("external", playlistId), arrayOf( - MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0 + Members.AUDIO_ID, // 0 AudioColumns.TITLE, // 1 AudioColumns.TRACK, // 2 AudioColumns.YEAR, // 3 @@ -114,10 +120,10 @@ object PlaylistSongsLoader { AudioColumns.ALBUM, // 8 AudioColumns.ARTIST_ID, // 9 AudioColumns.ARTIST, // 10 - MediaStore.Audio.Playlists.Members._ID,//11 + Members._ID,//11 AudioColumns.COMPOSER,//12 "album_artist"//13 - ), IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER + ), IS_MUSIC, null, Members.DEFAULT_SORT_ORDER ) } catch (e: SecurityException) { return null diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 7ea0db79..fb549aa4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -41,10 +41,10 @@ interface Repository { fun historySong(): List fun favorites(): LiveData> fun observableHistorySongs(): LiveData> - fun albumById(albumId: Int): Album + fun albumById(albumId: Long): Album fun playlistSongs(playlistEntity: PlaylistEntity): LiveData> suspend fun fetchAlbums(): List - suspend fun albumByIdAsync(albumId: Int): Album + suspend fun albumByIdAsync(albumId: Long): Album suspend fun allSongs(): List suspend fun fetchArtists(): List suspend fun albumArtists(): List @@ -52,10 +52,10 @@ interface Repository { suspend fun fetchGenres(): List suspend fun search(query: String?): MutableList suspend fun getPlaylistSongs(playlist: Playlist): List - suspend fun getGenre(genreId: Int): List + suspend fun getGenre(genreId: Long): List suspend fun artistInfo(name: String, lang: String?, cache: String?): Result suspend fun albumInfo(artist: String, album: String): Result - suspend fun artistById(artistId: Int): Artist + suspend fun artistById(artistId: Long): Artist suspend fun recentArtists(): List suspend fun topArtists(): List suspend fun topAlbums(): List @@ -70,7 +70,7 @@ interface Repository { suspend fun playlists(): Home suspend fun homeSections(): List suspend fun homeSectionsFlow(): Flow>> - suspend fun playlist(playlistId: Int): Playlist + suspend fun playlist(playlistId: Long): Playlist suspend fun fetchPlaylistWithSongs(): List suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List suspend fun insertSongs(songs: List) @@ -78,7 +78,7 @@ interface Repository { suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun fetchPlaylists(): List suspend fun deleteRoomPlaylist(playlists: List) - suspend fun renameRoomPlaylist(playlistId: Int, name: String) + suspend fun renameRoomPlaylist(playlistId: Long, name: String) suspend fun deleteSongsInPlaylist(songs: List) suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun deletePlaylistSongs(playlists: List) @@ -93,7 +93,7 @@ interface Repository { suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) - suspend fun checkSongExistInPlayCount(songId: Int): List + suspend fun checkSongExistInPlayCount(songId: Long): List suspend fun playCountSongs(): List suspend fun blackListPaths(): List suspend fun lyrics(artist: String, title: String): Result @@ -126,15 +126,15 @@ class RealRepository( override suspend fun fetchAlbums(): List = 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 = artistRepository.artists() override suspend fun albumArtists(): List = 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 = lastAddedRepository.recentArtists() @@ -160,7 +160,7 @@ class RealRepository( PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) } - override suspend fun getGenre(genreId: Int): List = genreRepository.songs(genreId) + override suspend fun getGenre(genreId: Long): List = genreRepository.songs(genreId) override suspend fun artistInfo( name: String, @@ -235,7 +235,7 @@ class RealRepository( } - override suspend fun playlist(playlistId: Int) = + override suspend fun playlist(playlistId: Long) = playlistRepository.playlist(playlistId) override suspend fun fetchPlaylistWithSongs(): List = @@ -263,7 +263,7 @@ class RealRepository( override suspend fun deleteRoomPlaylist(playlists: List) = roomRepository.deletePlaylistEntities(playlists) - override suspend fun renameRoomPlaylist(playlistId: Int, name: String) = + override suspend fun renameRoomPlaylist(playlistId: Long, name: String) = roomRepository.renamePlaylistEntity(playlistId, name) override suspend fun deleteSongsInPlaylist(songs: List) = @@ -306,7 +306,7 @@ class RealRepository( override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = roomRepository.deleteSongInPlayCount(playCountEntity) - override suspend fun checkSongExistInPlayCount(songId: Int): List = + override suspend fun checkSongExistInPlayCount(songId: Long): List = roomRepository.checkSongExistInPlayCount(songId) override suspend fun playCountSongs(): List = diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 16100176..f2e86636 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -18,7 +18,7 @@ interface RoomRepository { suspend fun playlistWithSongs(): List suspend fun insertSongs(songs: List) suspend fun deletePlaylistEntities(playlistEntities: List) - suspend fun renamePlaylistEntity(playlistId: Int, name: String) + suspend fun renamePlaylistEntity(playlistId: Long, name: String) suspend fun deleteSongsInPlaylist(songs: List) suspend fun deletePlaylistSongs(playlists: List) suspend fun favoritePlaylist(favorite: String): PlaylistEntity @@ -31,7 +31,7 @@ interface RoomRepository { suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) - suspend fun checkSongExistInPlayCount(songId: Int): List + suspend fun checkSongExistInPlayCount(songId: Long): List suspend fun playCountSongs(): List suspend fun insertBlacklistPath(blackListStoreEntities: List) suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) @@ -76,7 +76,7 @@ class RealRoomRepository( override suspend fun deletePlaylistEntities(playlistEntities: List) = playlistDao.deletePlaylists(playlistEntities) - override suspend fun renamePlaylistEntity(playlistId: Int, name: String) = + override suspend fun renamePlaylistEntity(playlistId: Long, name: String) = playlistDao.renamePlaylist(playlistId, name) override suspend fun deleteSongsInPlaylist(songs: List) { @@ -95,7 +95,7 @@ class RealRoomRepository( return if (playlist != null) { playlist } else { - createPlaylist(PlaylistEntity(favorite)) + createPlaylist(PlaylistEntity(playlistName = favorite)) playlistDao.isPlaylistExists(favorite).first() } } @@ -143,7 +143,7 @@ class RealRoomRepository( override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = playCountDao.deleteSongInPlayCount(playCountEntity) - override suspend fun checkSongExistInPlayCount(songId: Int): List = + override suspend fun checkSongExistInPlayCount(songId: Long): List = playCountDao.checkSongExistInPlayCount(songId) override suspend fun playCountSongs(): List = diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index 10165a7f..a8a5f83b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -17,9 +17,14 @@ package code.name.monkey.retromusic.repository import android.content.Context import android.database.Cursor 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.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.providers.BlacklistStore import code.name.monkey.retromusic.util.PreferenceUtil @@ -40,7 +45,7 @@ interface SongRepository { fun song(cursor: Cursor?): Song - fun song(songId: Int): Song + fun song(songId: Long): Song } 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%"))) } - override fun song(songId: Int): Song { + override fun song(songId: Long): Song { return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString()))) } override fun songsByFilePath(filePath: String): List { return songs( makeSongCursor( - MediaStore.Audio.AudioColumns.DATA + "=?", + AudioColumns.DATA + "=?", arrayOf(filePath) ) ) @@ -90,19 +95,19 @@ class RealSongRepository(private val context: Context) : SongRepository { private fun getSongFromCursorImpl( cursor: Cursor ): Song { - val id = cursor.getInt(0) - val title = cursor.getString(1) - val trackNumber = cursor.getInt(2) - val year = cursor.getInt(3) - val duration = cursor.getLong(4) - val data = cursor.getString(5) - val dateModified = cursor.getLong(6) - val albumId = cursor.getInt(7) - val albumName = cursor.getString(8) - val artistId = cursor.getInt(9) - val artistName = cursor.getString(10) - val composer = cursor.getString(11) - val albumArtist = cursor.getString(12) + val id = cursor.getLong(AudioColumns._ID) + val title = cursor.getString(AudioColumns.TITLE) + val trackNumber = cursor.getInt(AudioColumns.TRACK) + val year = cursor.getInt(AudioColumns.YEAR) + val duration = cursor.getLong(AudioColumns.DURATION) + val data = cursor.getString(AudioColumns.DATA) + val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) + val albumId = cursor.getLong(AudioColumns.ALBUM_ID) + val albumName = cursor.getStringOrNull(AudioColumns.ALBUM) + val artistId = cursor.getLong(AudioColumns.ARTIST_ID) + val artistName = cursor.getStringOrNull(AudioColumns.ARTIST) + val composer = cursor.getStringOrNull(AudioColumns.COMPOSER) + val albumArtist = cursor.getStringOrNull("album_artist") return Song( id, title, @@ -142,10 +147,10 @@ class RealSongRepository(private val context: Context) : SongRepository { selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths) } selectionFinal = - selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) + selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) try { return context.contentResolver.query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + Media.EXTERNAL_CONTENT_URI, baseProjection, selectionFinal, selectionValuesFinal, diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt index 00ed323b..6a9bcb70 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt @@ -90,7 +90,7 @@ class MediaSessionCallback( } } - private fun checkAndStartPlaying(songs: ArrayList, itemId: Int) { + private fun checkAndStartPlaying(songs: ArrayList, itemId: Long) { var songIndex = MusicUtil.indexOfSongInList(songs, itemId) if (songIndex == -1) { songIndex = 0 diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java index eff55a60..917e4c30 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -618,7 +618,7 @@ public class MusicService extends Service implements break; case SHUFFLE_MODE_NONE: this.shuffleMode = shuffleMode; - int currentSongId = Objects.requireNonNull(getCurrentSong()).getId(); + long currentSongId = Objects.requireNonNull(getCurrentSong()).getId(); playingQueue = new ArrayList<>(originalPlayingQueue); int newPosition = 0; if (getPlayingQueue() != null) { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java b/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java index c8115e81..b0ee4cf5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java @@ -34,7 +34,7 @@ public class AutoGeneratedPlaylistBitmap { if (songPlaylist == null) return null; long start = System.currentTimeMillis(); // lấy toàn bộ album id, loại bỏ trùng nhau - ArrayList albumID = new ArrayList<>(); + List albumID = new ArrayList<>(); for (Song song : songPlaylist) { if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId()); } @@ -42,8 +42,8 @@ public class AutoGeneratedPlaylistBitmap { long start2 = System.currentTimeMillis() - start; // lấy toàn bộ art tồn tại - ArrayList art = new ArrayList(); - for (Integer id : albumID) { + List art = new ArrayList(); + for (Long id : albumID) { Bitmap bitmap = getBitmapWithAlbumId(context, id); if (bitmap != null) art.add(bitmap); if (art.size() == 6) break; @@ -168,7 +168,7 @@ public class AutoGeneratedPlaylistBitmap { else return bitmap; } - private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Integer id) { + private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) { try { return Glide.with(context) .load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id)) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index a29663a1..0af7cb91 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -16,6 +16,7 @@ import androidx.core.content.FileProvider import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R 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.model.Artist import code.name.monkey.retromusic.model.Playlist @@ -85,7 +86,7 @@ object MusicUtil : KoinComponent { return albumArtDir } - fun deleteAlbumArt(context: Context, albumId: Int) { + fun deleteAlbumArt(context: Context, albumId: Long) { val contentResolver = context.contentResolver val localUri = Uri.parse("content://media/external/audio/albumart") contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null) @@ -175,10 +176,9 @@ object MusicUtil : KoinComponent { return lyrics } - fun getMediaStoreAlbumCoverUri(albumId: Int): Uri { - val sArtworkUri = - Uri.parse("content://media/external/audio/albumart") - return ContentUris.withAppendedId(sArtworkUri, albumId.toLong()) + fun getMediaStoreAlbumCoverUri(albumId: Long): Uri { + val sArtworkUri = Uri.parse("content://media/external/audio/albumart") + return ContentUris.withAppendedId(sArtworkUri, albumId) } @@ -249,7 +249,7 @@ object MusicUtil : KoinComponent { return "$songCount $songString" } - fun getSongFileUri(songId: Int): Uri { + fun getSongFileUri(songId: Long): Uri { return ContentUris.withAppendedId( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId.toLong() @@ -268,18 +268,13 @@ object MusicUtil : KoinComponent { return if (year > 0) year.toString() else "-" } - fun indexOfSongInList(songs: List, songId: Int): Int { - for (i in songs.indices) { - if (songs[i].id == songId) { - return i - } - } - return -1 + fun indexOfSongInList(songs: List, songId: Long): Int { + return songs.indexOfFirst { it.id == songId } } fun insertAlbumArt( context: Context, - albumId: Int, + albumId: Long, path: String? ) { val contentResolver = context.contentResolver @@ -306,7 +301,7 @@ object MusicUtil : KoinComponent { fun isFavorite(context: Context, song: Song): Boolean { return PlaylistsUtil - .doPlaylistContains(context, getFavoritesPlaylist(context).id.toLong(), song.id) + .doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id) } fun isFavoritePlaylist( @@ -387,7 +382,7 @@ object MusicUtil : KoinComponent { // as from the album art cache cursor.moveToFirst() while (!cursor.isAfterLast) { - val id = cursor.getInt(0) + val id = cursor.getLong(BaseColumns._ID) val song: Song = songRepository.song(id) removeFromQueue(song) cursor.moveToNext() @@ -452,7 +447,7 @@ object MusicUtil : KoinComponent { // as from the album art cache cursor.moveToFirst() while (!cursor.isAfterLast) { - val id: Int = cursor.getInt(0) + val id = cursor.getLong(BaseColumns._ID) val song: Song = RealSongRepository(context).song(id) removeFromQueue(song) cursor.moveToNext() diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java index cc2dad88..cfff22d3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java @@ -43,7 +43,7 @@ import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; 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; if (name != null && name.length() > 0) { 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 helperList = new ArrayList<>(); helperList.add(song); addToPlaylist(context, helperList, playlistId, showToastOnFinish); } - public static void addToPlaylist(@NonNull final Context context, @NonNull final List songs, final int playlistId, final boolean showToastOnFinish) { + public static void addToPlaylist(@NonNull final Context context, @NonNull final List songs, final long playlistId, final boolean showToastOnFinish) { final int size = songs.size(); final ContentResolver resolver = context.getContentResolver(); final String[] projection = new String[]{ @@ -180,7 +180,7 @@ public class PlaylistsUtil { 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( "external", playlistId); 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 songs) { - final int playlistId = songs.get(0).getPlaylistId(); + final long playlistId = songs.get(0).getPlaylistId(); Uri uri = MediaStore.Audio.Playlists.Members.getContentUri( "external", playlistId); 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) { try { Cursor c = context.getContentResolver().query( @@ -229,7 +229,7 @@ public class PlaylistsUtil { 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(), playlistId, from, to); } diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index 9876285b..bd9c0e75 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -32,7 +32,7 @@ tools:layout="@layout/fragment_album_details"> + app:argType="long" /> + app:argType="long" />