diff --git a/app/build.gradle b/app/build.gradle index 37bcac79..a75cecfd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -107,6 +107,7 @@ dependencies { implementation 'androidx.palette:palette-ktx:1.0.0' def nav_version = "2.3.0" + implementation "androidx.navigation:navigation-runtime-ktx:$nav_version" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json index 2efd2450..b7620161 100644 --- a/app/src/main/assets/contributors.json +++ b/app/src/main/assets/contributors.json @@ -13,13 +13,13 @@ }, { "name": "Daksh P. Jain", - "summary": "Telegram group maintainer", - "link": "https://dakshpjain.eu.org", + "summary": "Support Representative & Moderator", + "link": "https://daksh.eu.org", "profile_image": "https://i.imgur.com/fnYpg65.jpg" }, { "name": "Milind Goel", - "summary": "Github & Telegram maintainer", + "summary": "Support Representative & Moderator", "link": "https://t.me/MilindGoel15", "profile_image": "https://i.imgur.com/Bz4De21_d.jpg" } 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 eef1b393..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 @@ -28,8 +28,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis const val APP_UPDATE_REQUEST_CODE = 9002 } - private var blockRequestPermissions = false - override fun createContentView(): View { return wrapSlidingMusicPanel(R.layout.activity_main_content) } @@ -64,14 +62,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis } } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (!hasPermissions()) { - //requestPermissions() - } - } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { if (key == GENERAL_THEME || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES ) { @@ -107,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) @@ -116,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, @@ -145,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): List { val songs = ArrayList() for (album in albums) { - songs.addAll(album.songs!!) + songs.addAll(album.songs) } return songs } @@ -170,8 +170,7 @@ open class AlbumAdapter( if (isInQuickSelectMode) { toggleChecked(layoutPosition) } else { - println(dataSet[layoutPosition].id) - image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) } + albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index 1a82f465..2ee9ddb2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -9,7 +9,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.LyricsDialog import code.name.monkey.retromusic.fragments.AlbumCoverStyle import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.glide.RetroMusicColoredTarget @@ -91,7 +90,7 @@ class AlbumCoverPagerAdapter( val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false) albumCover = view.findViewById(R.id.player_image) albumCover.setOnClickListener { - LyricsDialog().show(childFragmentManager, "LyricsDialog") + //LyricsDialog().show(childFragmentManager, "LyricsDialog") showLyricsDialog() } return view diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java index ddf99c21..87460143 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java @@ -113,6 +113,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold itemView.setOnLongClickListener(this); } + @Nullable @Override public View getSwipeableContainerView() { return null; @@ -129,11 +130,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold } public void setImageTransitionName(@NonNull String transitionName) { - if (imageContainerCard != null) { + itemView.setTransitionName(transitionName); + /* if (imageContainerCard != null) { imageContainerCard.setTransitionName(transitionName); } if (image != null) { image.setTransitionName(transitionName); - } + }*/ } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index 6407a626..a806c72a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R.menu import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.interfaces.CabHolder diff --git a/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt index 5ea731a2..97288235 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt @@ -13,7 +13,7 @@ interface HistoryDao { suspend fun insertSongInHistory(historyEntity: HistoryEntity) @Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1") - suspend fun isSongPresentInHistory(songId: Int): HistoryEntity? + suspend fun isSongPresentInHistory(songId: Long): HistoryEntity? @Update suspend fun updateHistorySong(historyEntity: HistoryEntity) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/HistoryEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/HistoryEntity.kt index bbb2471f..a4facd79 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/HistoryEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/HistoryEntity.kt @@ -7,7 +7,7 @@ import androidx.room.PrimaryKey @Entity class HistoryEntity( @PrimaryKey - val id: Int, + val id: Long, val title: String, @ColumnInfo(name = "track_number") val trackNumber: Int, @@ -17,11 +17,11 @@ class HistoryEntity( @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/PlayCountDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt index 0c3fbbae..4107b7ba 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt @@ -14,14 +14,14 @@ interface PlayCountDao { fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) @Query("SELECT * FROM PlayCountEntity WHERE id =:songId") - fun checkSongExistInPlayCount(songId: Int): List + 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..03666f0a 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,83 +8,121 @@ fun List.toSongs(): List { } } -fun List.toSongs(playlistId: Int): List { +fun List.toSongs(playlistId: Long): List { return map { it.toSongEntity(playlistId) } } +fun Song.toHistoryEntity(timePlayed: Long): HistoryEntity { + return HistoryEntity( + 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 Song.toSongEntity(playListId: Long): SongEntity { + return SongEntity( + 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 + ) +} + 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..d1e86e12 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 @@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extra import code.name.monkey.retromusic.extensions.materialDialog @@ -56,8 +57,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..7824826b 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 @@ -3,8 +3,11 @@ package code.name.monkey.retromusic.fragments import android.os.Bundle import android.view.View import android.widget.ImageView +import androidx.core.os.bundleOf import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.FragmentNavigatorExtras +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager @@ -178,11 +181,21 @@ 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) { + findNavController().navigate( + R.id.artistDetailsFragment, + bundleOf(EXTRA_ARTIST_ID to artistId), + null, + FragmentNavigatorExtras(imageView to getString(R.string.transition_artist_image)) + ) } - 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), + null, + FragmentNavigatorExtras(view to getString(R.string.transition_album_art)) + ) } } \ 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 ffccd49c..f3b609b4 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 @@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.SongEntity +import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.fragments.ReloadType.* import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.MusicServiceEventListener @@ -75,7 +76,6 @@ class LibraryViewModel( } fun getHome(): LiveData> { - fetchHomeSections() return home } @@ -184,7 +184,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) } @@ -200,8 +200,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) @@ -224,9 +224,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 fefdf40a..3ae09641 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 @@ -10,6 +10,7 @@ import androidx.core.text.HtmlCompat import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController +import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DefaultItemAnimator @@ -46,6 +47,8 @@ import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.Glide +import com.google.android.material.transition.platform.MaterialArcMotion +import com.google.android.material.transition.platform.MaterialContainerTransform import kotlinx.android.synthetic.main.fragment_album_content.* import kotlinx.android.synthetic.main.fragment_album_details.* import kotlinx.coroutines.Dispatchers @@ -70,8 +73,16 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det private val savedSortOrder: String get() = PreferenceUtil.albumDetailSongSortOrder - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + sharedElementEnterTransition = MaterialContainerTransform().apply { + duration = 1000L + pathMotion = MaterialArcMotion() + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) setHasOptionsMenu(true) mainActivity.hideBottomBarVisibility(false) mainActivity.addMusicServiceEventListener(detailsViewModel) @@ -79,7 +90,6 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det toolbar.title = " " postponeEnterTransition() detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { - println(Thread.currentThread().name) startPostponedEnterTransition() showAlbum(it) }) @@ -92,11 +102,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det bundleOf(EXTRA_ARTIST_ID to album.artistId) ) } - playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) } + playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs, 0, true) } shuffleAction.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue( - album.songs!!, + album.songs, true ) } @@ -135,7 +145,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det } private fun showAlbum(album: Album) { - if (album.songs!!.isEmpty()) { + if (album.songs.isEmpty()) { return } this.album = album @@ -255,10 +265,12 @@ 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) + bundleOf(EXTRA_ALBUM_ID to albumId), + null, + FragmentNavigatorExtras(view to getString(R.string.transition_album_art)) ) } @@ -350,29 +362,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 8f4e4197..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,15 +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) { - val album = repository.albumByIdAsync(albumId) - emit(album) + 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) } @@ -32,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..251fc752 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 @@ -16,11 +16,17 @@ import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil +import com.google.android.material.transition.platform.MaterialFadeThrough class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(), AlbumClickListener { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer { @@ -43,7 +49,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..7f162d93 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 @@ -15,10 +15,15 @@ import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeF import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil +import com.google.android.material.transition.platform.MaterialFadeThrough class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment(), ArtistClickListener { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -46,7 +51,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index 460731af..c8d6dde5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -36,6 +36,7 @@ import code.name.monkey.retromusic.glide.UserProfileGlideRequest import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Glide +import com.google.android.material.transition.platform.MaterialFadeThrough import kotlinx.android.synthetic.main.abs_playlists.* import kotlinx.android.synthetic.main.fragment_banner_home.* import kotlinx.android.synthetic.main.home_content.* @@ -43,6 +44,10 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel class HomeFragment : AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } private val libraryViewModel: LibraryViewModel by sharedViewModel() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt index 0eacbb9a..1800df08 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt @@ -14,12 +14,16 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.ViewCompat +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.SongEntity +import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.ripAlpha import code.name.monkey.retromusic.extensions.show @@ -36,7 +40,7 @@ import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor -import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetBehavior.* import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager @@ -45,6 +49,9 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils import kotlinx.android.synthetic.main.fragment_gradient_controls.* import kotlinx.android.synthetic.main.fragment_gradient_player.* import kotlinx.android.synthetic.main.status_bar.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player), MusicProgressViewUpdateHelper.Callback, @@ -61,7 +68,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private var playingQueueAdapter: PlayingQueueAdapter? = null private lateinit var linearLayoutManager: LinearLayoutManager - private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() { + private val bottomSheetCallbackList = object : BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { mainActivity.getBottomSheetBehavior().setAllowDragging(false) playerQueueSheet.setPadding( @@ -74,11 +81,11 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun onStateChanged(bottomSheet: View, newState: Int) { when (newState) { - BottomSheetBehavior.STATE_EXPANDED, - BottomSheetBehavior.STATE_DRAGGING -> { + STATE_EXPANDED, + STATE_DRAGGING -> { mainActivity.getBottomSheetBehavior().setAllowDragging(false) } - BottomSheetBehavior.STATE_COLLAPSED -> { + STATE_COLLAPSED -> { resetToCurrentPosition() mainActivity.getBottomSheetBehavior().setAllowDragging(true) } @@ -167,9 +174,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun onBackPressed(): Boolean { var wasExpanded = false - if (getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED) { - wasExpanded = getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED - getQueuePanel().state = BottomSheetBehavior.STATE_COLLAPSED + if (getQueuePanel().state == STATE_EXPANDED) { + wasExpanded = getQueuePanel().state == STATE_EXPANDED + getQueuePanel().state = STATE_COLLAPSED return wasExpanded } return wasExpanded @@ -216,7 +223,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun toggleFavorite(song: Song) { super.toggleFavorite(song) if (song.id == MusicPlayerRemote.currentSong.id) { - updateIsFavorite() + updateIsFavoriteIcon() } } @@ -224,6 +231,23 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play toggleFavorite(MusicPlayerRemote.currentSong) } + private fun updateIsFavoriteIcon() { + lifecycleScope.launch(Dispatchers.IO) { + val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist() + if (playlist != null) { + val song: SongEntity = + MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) + val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty() + withContext(Dispatchers.Main) { + val icon = + if (isFavorite) R.drawable.ic_favorite + else R.drawable.ic_favorite_border + songFavourite.setImageResource(icon) + } + } + } + } + private fun hideVolumeIfAvailable() { if (PreferenceUtil.isVolumeVisibilityMode) { childFragmentManager.beginTransaction() @@ -241,6 +265,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play updatePlayPauseDrawableState() updatePlayPauseDrawableState() updateQueue() + updateIsFavoriteIcon() } override fun onPlayStateChanged() { @@ -259,6 +284,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play super.onPlayingMetaChanged() updateSong() updateQueuePosition() + updateIsFavoriteIcon() } override fun onQueueChanged() { @@ -359,13 +385,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private fun updateLabel() { (MusicPlayerRemote.playingQueue.size - 1).apply { if (this == (MusicPlayerRemote.position)) { - nextSong.hide() + nextSong.text = "Last song" } else { val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title - nextSong.apply { - text = title - show() - } + nextSong.text = title } } } @@ -460,12 +483,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun onUpdateProgressViews(progress: Int, total: Int) { progressSlider.max = total - val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress) animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME animator.interpolator = LinearInterpolator() animator.start() - songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt deleted file mode 100644 index efe3c4e4..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt +++ /dev/null @@ -1,72 +0,0 @@ -package code.name.monkey.retromusic.fragments.playlists - -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.View -import android.widget.Toast -import androidx.lifecycle.Observer -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.LinearLayoutManager -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.adapter.playlist.LegacyPlaylistAdapter -import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.fragments.ReloadType.Playlists -import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment -import code.name.monkey.retromusic.model.Playlist -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch - -class ImportPlaylistFragment : - AbsRecyclerViewFragment(), - LegacyPlaylistAdapter.PlaylistClickListener { - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - libraryViewModel.getLegacyPlaylist().observe(viewLifecycleOwner, Observer { - if (it.isNotEmpty()) - adapter?.swapData(it) - else - adapter?.swapData(listOf()) - }) - } - - override fun createLayoutManager(): LinearLayoutManager { - return LinearLayoutManager(requireContext()) - } - - override fun createAdapter(): LegacyPlaylistAdapter { - return LegacyPlaylistAdapter( - requireActivity(), - ArrayList(), - R.layout.item_list_no_image, - this - ) - } - - override fun onPlaylistClick(playlist: Playlist) { - Toast.makeText(requireContext(), "Importing ${playlist.name}", Toast.LENGTH_LONG).show() - lifecycleScope.launch(IO) { - if (playlist.name.isNotEmpty()) { - if (libraryViewModel.checkPlaylistExists(playlist.name).isEmpty()) { - val playlistId: Long = - libraryViewModel.createPlaylist(PlaylistEntity(playlist.name)) - libraryViewModel.insertSongs(playlist.getSongs().map { - it.toSongEntity(playlistId.toInt()) - }) - libraryViewModel.forceReload(Playlists) - } else { - Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) - .show() - } - } - } - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - menu.removeItem(R.id.action_grid_size) - menu.removeItem(R.id.action_layout_type) - menu.removeItem(R.id.action_sort_order) - super.onCreateOptionsMenu(menu, inflater) - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 95f849a2..932066a0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -11,9 +11,14 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment +import com.google.android.material.transition.platform.MaterialFadeThrough import kotlinx.android.synthetic.main.fragment_library.* class PlaylistsFragment : AbsRecyclerViewFragment() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt index 50681023..adeb09c8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt @@ -15,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel() fun search(query: String?) = viewModelScope.launch(IO) { val result = realRepository.search(query) - results.value = result + results.postValue(result) } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index 533aa0f7..80ccb8d7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -12,10 +12,14 @@ import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeF import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil +import com.google.android.material.transition.platform.MaterialFadeThrough class SongsFragment : AbsRecyclerViewCustomGridSizeFragment() { - + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialFadeThrough() + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.kt index 8df825ca..3d62ca5c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/AbsCustomPlaylist.kt @@ -7,8 +7,8 @@ import org.koin.core.KoinComponent import org.koin.core.inject abstract class AbsCustomPlaylist( - id: Int = -1, - name: String = "" + id: Long, + name: String ) : Playlist(id, name), KoinComponent { abstract fun songs(): List 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..bb4fd0b1 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 @@ -15,17 +15,20 @@ package code.name.monkey.retromusic.model import code.name.monkey.retromusic.util.MusicUtil +import code.name.monkey.retromusic.util.PreferenceUtil 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() { val name = safeGetFirstAlbum().safeGetFirstSong().albumArtist + if (PreferenceUtil.albumArtistsOnly && MusicUtil.isVariousArtists(name)) { + return VARIOUS_ARTISTS_DISPLAY_NAME + } return if (MusicUtil.isArtistNameUnknown(name)) { UNKNOWN_ARTIST_DISPLAY_NAME } else safeGetFirstAlbum().safeGetFirstSong().artistName @@ -34,37 +37,27 @@ 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" + const val VARIOUS_ARTISTS_DISPLAY_NAME = "Various Artists" + const val VARIOUS_ARTISTS_ID : Long = -2 + 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..8c1481e1 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,58 +18,64 @@ 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 - ) + + + // 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 } - fun toSongEntity(playListId: Int): SongEntity { - return SongEntity( - playListId, - id, - title, - trackNumber, - year, - duration, - data, - dateModified, - albumId, - albumName, - artistId, - artistName, - composer, - albumArtist - ) + 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 } @@ -77,19 +83,19 @@ open class Song( @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 bf1b41e3..f0fd932f 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( @@ -39,7 +39,29 @@ class RealArtistRepository( PreferenceUtil.artistAlbumSortOrder + ", " + PreferenceUtil.artistSongSortOrder } + override fun artist(artistId: Long): Artist { + if (artistId == Artist.VARIOUS_ARTISTS_ID) { + // Get Various Artists + val songs = songRepository.songs( + songRepository.makeSongCursor( + null, + null, + getSongLoaderSortOrder() + ) + ) + val albums = albumRepository.splitIntoAlbums(songs).filter { it.albumArtist == Artist.VARIOUS_ARTISTS_DISPLAY_NAME } + return Artist(Artist.VARIOUS_ARTISTS_ID, albums) + } + val songs = songRepository.songs( + songRepository.makeSongCursor( + AudioColumns.ARTIST_ID + "=?", + arrayOf(artistId.toString()), + getSongLoaderSortOrder() + ) + ) + return Artist(artistId, albumRepository.splitIntoAlbums(songs)) + } override fun artists(): List { val songs = songRepository.songs( songRepository.makeSongCursor( @@ -50,17 +72,6 @@ class RealArtistRepository( return splitIntoArtists(albumRepository.splitIntoAlbums(songs)) } - override fun artists(query: String): List { - val songs = songRepository.songs( - songRepository.makeSongCursor( - AudioColumns.ARTIST + " LIKE ?", - arrayOf("%$query%"), - getSongLoaderSortOrder() - ) - ) - return splitIntoArtists(albumRepository.splitIntoAlbums(songs)) - } - override fun albumArtists(): List { val songs = songRepository.songs( songRepository.makeSongCursor( @@ -70,54 +81,41 @@ class RealArtistRepository( ) ) - val sortString = if (PreferenceUtil.artistSortOrder.contains("DESC")) String.CASE_INSENSITIVE_ORDER.reversed() else String.CASE_INSENSITIVE_ORDER - - return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs)).sortedWith(compareBy(sortString) { it.name }) + return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs)) } - 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 ArrayList(amap.values) - } - - override fun artist(artistId: Int): Artist { + override fun artists(query: String): List { val songs = songRepository.songs( songRepository.makeSongCursor( - AudioColumns.ARTIST_ID + "=?", - arrayOf(artistId.toString()), + AudioColumns.ARTIST + " LIKE ?", + arrayOf("%$query%"), getSongLoaderSortOrder() ) ) - return Artist(ArrayList(albumRepository.splitIntoAlbums(songs))) + return splitIntoArtists(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) + + private fun splitIntoAlbumArtists(albums: List): List { + return albums.groupBy { it.albumArtist } + .map { + val currentAlbums = it.value + if (currentAlbums.isNotEmpty()) { + if (currentAlbums[0].albumArtist == Artist.VARIOUS_ARTISTS_DISPLAY_NAME) { + Artist(Artist.VARIOUS_ARTISTS_ID, currentAlbums) + } else { + Artist(currentAlbums[0].artistId, currentAlbums) + } + } else { + Artist.empty + } } - } - return artists } - 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 + + + fun splitIntoArtists(albums: List): List { + return albums.groupBy { it.artistId } + .map { Artist(it.key, it.value) } } -} +} \ No newline at end of file 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..5f215670 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,14 @@ import android.content.ContentResolver import android.database.Cursor import android.provider.BaseColumns import android.provider.MediaStore +import android.provider.MediaStore.Audio.AudioColumns +import android.provider.MediaStore.Audio.Playlists.* import android.provider.MediaStore.Audio.PlaylistsColumns 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 +46,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 +58,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 +108,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 +120,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 +138,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.getStringOrNull(AudioColumns.COMPOSER) + val albumArtist = cursor.getStringOrNull("album_artist") return PlaylistSong( id, title, @@ -160,7 +167,7 @@ class RealPlaylistRepository( artistName, playlistId, idInPlaylist, - composer, + composer ?: "", albumArtist ) } @@ -170,37 +177,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..4a6eb42d 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) @@ -70,13 +70,13 @@ class RealRoomRepository( } - override fun getSongs(playlistEntity: PlaylistEntity): LiveData> = + override fun getSongs(playlistEntity: PlaylistEntity): LiveData> = playlistDao.songsFromPlaylist(playlistEntity.playListId) 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..3155c84b 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 @@ -18,8 +18,13 @@ import android.content.Context import android.database.Cursor import android.provider.MediaStore import android.provider.MediaStore.Audio.AudioColumns +import android.provider.MediaStore.Audio.Media 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,18 +147,15 @@ class RealSongRepository(private val context: Context) : SongRepository { selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths) } selectionFinal = - selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) - try { - return context.contentResolver.query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - baseProjection, - selectionFinal, - selectionValuesFinal, - sortOrder - ) - } catch (e: SecurityException) { - return null - } + selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) + + return context.contentResolver.query( + Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), + baseProjection, + selectionFinal, + selectionValuesFinal, + sortOrder + ) } private fun generateBlacklistSelection( 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..645b8843 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 @@ -304,9 +299,19 @@ object MusicUtil : KoinComponent { return tempName == "unknown" || tempName == "" } + fun isVariousArtists(artistName: String?): Boolean { + if (TextUtils.isEmpty(artistName)) { + return false + } + if (artistName == Artist.VARIOUS_ARTISTS_DISPLAY_NAME) { + return true + } + return false + } + 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 +392,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 +457,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/layout-land/fragment_album_details.xml b/app/src/main/res/layout-land/fragment_album_details.xml index 4b4d503e..3bae2be7 100644 --- a/app/src/main/res/layout-land/fragment_album_details.xml +++ b/app/src/main/res/layout-land/fragment_album_details.xml @@ -6,6 +6,7 @@ android:layout_height="match_parent" android:background="?attr/colorSurface" android:orientation="vertical" + android:transitionName="@string/transition_album_art" tools:ignore="UnusedAttribute"> + android:layout_height="match_parent" + android:transitionName="@string/transition_album_art"> diff --git a/app/src/main/res/navigation/library_graph.xml b/app/src/main/res/navigation/library_graph.xml index 3d670797..dd455bc4 100644 --- a/app/src/main/res/navigation/library_graph.xml +++ b/app/src/main/res/navigation/library_graph.xml @@ -41,9 +41,5 @@ android:label="" tools:layout="@layout/fragment_banner_home" /> - + \ No newline at end of file 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" /> +