Merge branch 'dev' of https://github.com/h4h13/RetroMusicPlayer into state
This commit is contained in:
commit
4493273c69
74 changed files with 862 additions and 792 deletions
|
@ -13,13 +13,13 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Daksh P. Jain",
|
"name": "Daksh P. Jain",
|
||||||
"summary": "Telegram group maintainer",
|
"summary": "Support Representative & Moderator",
|
||||||
"link": "https://daksh.eu.org",
|
"link": "https://daksh.eu.org",
|
||||||
"profile_image": "https://i.imgur.com/fnYpg65.jpg"
|
"profile_image": "https://i.imgur.com/fnYpg65.jpg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Milind Goel",
|
"name": "Milind Goel",
|
||||||
"summary": "Github & Telegram maintainer",
|
"summary": "Support Representative & Moderator",
|
||||||
"link": "https://t.me/MilindGoel15",
|
"link": "https://t.me/MilindGoel15",
|
||||||
"profile_image": "https://i.imgur.com/Bz4De21_d.jpg"
|
"profile_image": "https://i.imgur.com/Bz4De21_d.jpg"
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,14 +162,14 @@ private val viewModules = module {
|
||||||
LibraryViewModel(get())
|
LibraryViewModel(get())
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (albumId: Int) ->
|
viewModel { (albumId: Long) ->
|
||||||
AlbumDetailsViewModel(
|
AlbumDetailsViewModel(
|
||||||
get(),
|
get(),
|
||||||
albumId
|
albumId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (artistId: Int) ->
|
viewModel { (artistId: Long) ->
|
||||||
ArtistDetailsViewModel(
|
ArtistDetailsViewModel(
|
||||||
get(),
|
get(),
|
||||||
artistId
|
artistId
|
||||||
|
|
|
@ -97,8 +97,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
MusicPlayerRemote.playFromUri(uri)
|
MusicPlayerRemote.playFromUri(uri)
|
||||||
handled = true
|
handled = true
|
||||||
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
||||||
val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
|
val id = parseLongFromIntent(intent, "playlistId", "playlist")
|
||||||
if (id >= 0) {
|
if (id >= 0L) {
|
||||||
val position: Int = intent.getIntExtra("position", 0)
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
val songs: List<Song> =
|
val songs: List<Song> =
|
||||||
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
|
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
|
||||||
|
@ -106,19 +106,19 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
val id = parseLongFromIntent(intent, "albumId", "album")
|
||||||
if (id >= 0) {
|
if (id >= 0L) {
|
||||||
val position: Int = intent.getIntExtra("position", 0)
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
MusicPlayerRemote.openQueue(
|
MusicPlayerRemote.openQueue(
|
||||||
libraryViewModel.albumById(id).songs!!,
|
libraryViewModel.albumById(id).songs,
|
||||||
position,
|
position,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||||
val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
val id = parseLongFromIntent(intent, "artistId", "artist")
|
||||||
if (id >= 0) {
|
if (id >= 0L) {
|
||||||
val position: Int = intent.getIntExtra("position", 0)
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
MusicPlayerRemote.openQueue(
|
MusicPlayerRemote.openQueue(
|
||||||
libraryViewModel.artistById(id).songs,
|
libraryViewModel.artistById(id).songs,
|
||||||
|
@ -135,7 +135,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseIdFromIntent(
|
private fun parseLongFromIntent(
|
||||||
intent: Intent, longKey: String,
|
intent: Intent, longKey: String,
|
||||||
stringKey: String
|
stringKey: String
|
||||||
): Long {
|
): Long {
|
||||||
|
|
|
@ -40,7 +40,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
val repository by inject<Repository>()
|
val repository by inject<Repository>()
|
||||||
|
|
||||||
lateinit var saveFab: MaterialButton
|
lateinit var saveFab: MaterialButton
|
||||||
protected var id: Int = 0
|
protected var id: Long = 0
|
||||||
private set
|
private set
|
||||||
private var paletteColorPrimary: Int = 0
|
private var paletteColorPrimary: Int = 0
|
||||||
private var isInNoImageMode: Boolean = false
|
private var isInNoImageMode: Boolean = false
|
||||||
|
@ -251,7 +251,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
private fun getIntentExtras() {
|
private fun getIntentExtras() {
|
||||||
val intentExtras = intent.extras
|
val intentExtras = intent.extras
|
||||||
if (intentExtras != null) {
|
if (intentExtras != null) {
|
||||||
id = intentExtras.getInt(EXTRA_ID)
|
id = intentExtras.getLong(EXTRA_ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
|
class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.extensions.appHandleColor
|
import code.name.monkey.retromusic.extensions.appHandleColor
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.ImageUtil
|
import code.name.monkey.retromusic.util.ImageUtil
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
|
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
||||||
|
@ -168,12 +169,8 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSongPaths(): List<String> {
|
override fun getSongPaths(): List<String> {
|
||||||
val songs = repository.albumById(id).songs
|
return repository.albumById(id).songs
|
||||||
val paths = ArrayList<String>(songs!!.size)
|
.map(Song::data)
|
||||||
for (song in songs) {
|
|
||||||
paths.add(song.data)
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||||
|
|
|
@ -71,13 +71,13 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
|
||||||
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
|
||||||
CategoryInfo categoryInfo = categoryInfos.get(position);
|
CategoryInfo categoryInfo = categoryInfos.get(position);
|
||||||
|
|
||||||
holder.checkBox.setChecked(categoryInfo.visible);
|
holder.checkBox.setChecked(categoryInfo.isVisible());
|
||||||
holder.title.setText(holder.title.getResources().getString(categoryInfo.category.stringRes));
|
holder.title.setText(holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
|
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
|
||||||
categoryInfo.visible = !categoryInfo.visible;
|
categoryInfo.setVisible(!categoryInfo.isVisible());
|
||||||
holder.checkBox.setChecked(categoryInfo.visible);
|
holder.checkBox.setChecked(categoryInfo.isVisible());
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
|
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
|
@ -110,9 +110,9 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
|
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
|
||||||
if (categoryInfo.visible) {
|
if (categoryInfo.isVisible()) {
|
||||||
for (CategoryInfo c : categoryInfos) {
|
for (CategoryInfo c : categoryInfos) {
|
||||||
if (c != categoryInfo && c.visible) {
|
if (c != categoryInfo && c.isVisible()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ class HomeAdapter(
|
||||||
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
|
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
|
||||||
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
|
||||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
override fun onArtist(artistId: Long, imageView: ImageView) {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.artistDetailsFragment,
|
R.id.artistDetailsFragment,
|
||||||
bundleOf(EXTRA_ARTIST_ID to artistId),
|
bundleOf(EXTRA_ARTIST_ID to artistId),
|
||||||
|
@ -244,7 +244,7 @@ class HomeAdapter(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Long, view: View) {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
|
|
|
@ -136,7 +136,7 @@ open class AlbumAdapter(
|
||||||
private fun getSongList(albums: List<Album>): List<Song> {
|
private fun getSongList(albums: List<Album>): List<Song> {
|
||||||
val songs = ArrayList<Song>()
|
val songs = ArrayList<Song>()
|
||||||
for (album in albums) {
|
for (album in albums) {
|
||||||
songs.addAll(album.songs!!)
|
songs.addAll(album.songs)
|
||||||
}
|
}
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
@ -170,8 +170,7 @@ open class AlbumAdapter(
|
||||||
if (isInQuickSelectMode) {
|
if (isInQuickSelectMode) {
|
||||||
toggleChecked(layoutPosition)
|
toggleChecked(layoutPosition)
|
||||||
} else {
|
} else {
|
||||||
println(dataSet[layoutPosition].id)
|
albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView)
|
||||||
image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.R
|
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.AlbumCoverStyle
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
|
@ -91,7 +90,7 @@ class AlbumCoverPagerAdapter(
|
||||||
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
||||||
albumCover = view.findViewById(R.id.player_image)
|
albumCover = view.findViewById(R.id.player_image)
|
||||||
albumCover.setOnClickListener {
|
albumCover.setOnClickListener {
|
||||||
LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
//LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
||||||
showLyricsDialog()
|
showLyricsDialog()
|
||||||
}
|
}
|
||||||
return view
|
return view
|
||||||
|
|
|
@ -113,6 +113,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
|
||||||
itemView.setOnLongClickListener(this);
|
itemView.setOnLongClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View getSwipeableContainerView() {
|
public View getSwipeableContainerView() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -129,11 +130,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImageTransitionName(@NonNull String transitionName) {
|
public void setImageTransitionName(@NonNull String transitionName) {
|
||||||
if (imageContainerCard != null) {
|
itemView.setTransitionName(transitionName);
|
||||||
|
/* if (imageContainerCard != null) {
|
||||||
imageContainerCard.setTransitionName(transitionName);
|
imageContainerCard.setTransitionName(transitionName);
|
||||||
}
|
}
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
image.setTransitionName(transitionName);
|
image.setTransitionName(transitionName);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.R.menu
|
import code.name.monkey.retromusic.R.menu
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
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.db.toSongs
|
||||||
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
||||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface HistoryDao {
|
||||||
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
||||||
|
|
||||||
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
||||||
suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
|
suspend fun isSongPresentInHistory(songId: Long): HistoryEntity?
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
suspend fun updateHistorySong(historyEntity: HistoryEntity)
|
suspend fun updateHistorySong(historyEntity: HistoryEntity)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
||||||
@Entity
|
@Entity
|
||||||
class HistoryEntity(
|
class HistoryEntity(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
val id: Int,
|
val id: Long,
|
||||||
val title: String,
|
val title: String,
|
||||||
@ColumnInfo(name = "track_number")
|
@ColumnInfo(name = "track_number")
|
||||||
val trackNumber: Int,
|
val trackNumber: Int,
|
||||||
|
@ -17,11 +17,11 @@ class HistoryEntity(
|
||||||
@ColumnInfo(name = "date_modified")
|
@ColumnInfo(name = "date_modified")
|
||||||
val dateModified: Long,
|
val dateModified: Long,
|
||||||
@ColumnInfo(name = "album_id")
|
@ColumnInfo(name = "album_id")
|
||||||
val albumId: Int,
|
val albumId: Long,
|
||||||
@ColumnInfo(name = "album_name")
|
@ColumnInfo(name = "album_name")
|
||||||
val albumName: String,
|
val albumName: String,
|
||||||
@ColumnInfo(name = "artist_id")
|
@ColumnInfo(name = "artist_id")
|
||||||
val artistId: Int,
|
val artistId: Long,
|
||||||
@ColumnInfo(name = "artist_name")
|
@ColumnInfo(name = "artist_name")
|
||||||
val artistName: String,
|
val artistName: String,
|
||||||
val composer: String?,
|
val composer: String?,
|
||||||
|
|
|
@ -14,14 +14,14 @@ interface PlayCountDao {
|
||||||
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
|
||||||
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
|
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
|
||||||
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
|
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
|
||||||
fun playCountSongs(): List<PlayCountEntity>
|
fun playCountSongs(): List<PlayCountEntity>
|
||||||
|
|
||||||
@Query("DELETE FROM SongEntity WHERE id =:songId")
|
@Query("DELETE FROM SongEntity WHERE id =:songId")
|
||||||
fun deleteSong(songId: Int)
|
fun deleteSong(songId: Long)
|
||||||
|
|
||||||
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
|
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
|
||||||
fun updateQuantity(id: Int)
|
fun updateQuantity(id: Long)
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
||||||
@Entity
|
@Entity
|
||||||
class PlayCountEntity(
|
class PlayCountEntity(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
val id: Int,
|
val id: Long,
|
||||||
val title: String,
|
val title: String,
|
||||||
@ColumnInfo(name = "track_number")
|
@ColumnInfo(name = "track_number")
|
||||||
val trackNumber: Int,
|
val trackNumber: Int,
|
||||||
|
@ -17,11 +17,11 @@ class PlayCountEntity(
|
||||||
@ColumnInfo(name = "date_modified")
|
@ColumnInfo(name = "date_modified")
|
||||||
val dateModified: Long,
|
val dateModified: Long,
|
||||||
@ColumnInfo(name = "album_id")
|
@ColumnInfo(name = "album_id")
|
||||||
val albumId: Int,
|
val albumId: Long,
|
||||||
@ColumnInfo(name = "album_name")
|
@ColumnInfo(name = "album_name")
|
||||||
val albumName: String,
|
val albumName: String,
|
||||||
@ColumnInfo(name = "artist_id")
|
@ColumnInfo(name = "artist_id")
|
||||||
val artistId: Int,
|
val artistId: Long,
|
||||||
@ColumnInfo(name = "artist_name")
|
@ColumnInfo(name = "artist_name")
|
||||||
val artistName: String,
|
val artistName: String,
|
||||||
val composer: String?,
|
val composer: String?,
|
||||||
|
|
|
@ -9,7 +9,7 @@ interface PlaylistDao {
|
||||||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||||
|
|
||||||
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
|
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
|
||||||
suspend fun renamePlaylist(playlistId: Int, name: String)
|
suspend fun renamePlaylist(playlistId: Long, name: String)
|
||||||
|
|
||||||
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
|
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
|
||||||
fun isPlaylistExists(name: String): List<PlaylistEntity>
|
fun isPlaylistExists(name: String): List<PlaylistEntity>
|
||||||
|
@ -18,10 +18,10 @@ interface PlaylistDao {
|
||||||
suspend fun playlists(): List<PlaylistEntity>
|
suspend fun playlists(): List<PlaylistEntity>
|
||||||
|
|
||||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||||
suspend fun deletePlaylistSongs(playlistId: Int)
|
suspend fun deletePlaylistSongs(playlistId: Long)
|
||||||
|
|
||||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||||
suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int)
|
suspend fun deleteSongFromPlaylist(playlistId: Long, songId: Long)
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM PlaylistEntity")
|
@Query("SELECT * FROM PlaylistEntity")
|
||||||
|
@ -31,10 +31,10 @@ interface PlaylistDao {
|
||||||
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
|
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
|
||||||
|
|
||||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||||
suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List<SongEntity>
|
suspend fun isSongExistsInPlaylist(playlistId: Long, songId: Long): List<SongEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||||
fun songsFromPlaylist(playlistId: Int): LiveData<List<SongEntity>>
|
fun songsFromPlaylist(playlistId: Long): LiveData<List<SongEntity>>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
|
suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
|
||||||
|
@ -47,10 +47,10 @@ interface PlaylistDao {
|
||||||
|
|
||||||
|
|
||||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||||
fun favoritesSongsLiveData(playlistId: Int): LiveData<List<SongEntity>>
|
fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>>
|
||||||
|
|
||||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||||
fun favoritesSongs(playlistId: Int): List<SongEntity>
|
fun favoritesSongs(playlistId: Long): List<SongEntity>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,10 +9,9 @@ import kotlinx.android.parcel.Parcelize
|
||||||
@Entity
|
@Entity
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class PlaylistEntity(
|
class PlaylistEntity(
|
||||||
@ColumnInfo(name = "playlist_name")
|
|
||||||
val playlistName: String
|
|
||||||
) : Parcelable {
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo(name = "playlist_id")
|
@ColumnInfo(name = "playlist_id")
|
||||||
var playListId: Int = 0
|
val playListId: Long = 0,
|
||||||
}
|
@ColumnInfo(name = "playlist_name")
|
||||||
|
val playlistName: String
|
||||||
|
) : Parcelable
|
|
@ -10,9 +10,12 @@ import kotlinx.android.parcel.Parcelize
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)])
|
@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)])
|
||||||
class SongEntity(
|
class SongEntity(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
@ColumnInfo(name = "song_key")
|
||||||
|
val songPrimaryKey: Long = 0L,
|
||||||
@ColumnInfo(name = "playlist_creator_id")
|
@ColumnInfo(name = "playlist_creator_id")
|
||||||
val playlistCreatorId: Int,
|
val playlistCreatorId: Long,
|
||||||
val id: Int,
|
val id: Long,
|
||||||
val title: String,
|
val title: String,
|
||||||
@ColumnInfo(name = "track_number")
|
@ColumnInfo(name = "track_number")
|
||||||
val trackNumber: Int,
|
val trackNumber: Int,
|
||||||
|
@ -22,19 +25,15 @@ class SongEntity(
|
||||||
@ColumnInfo(name = "date_modified")
|
@ColumnInfo(name = "date_modified")
|
||||||
val dateModified: Long,
|
val dateModified: Long,
|
||||||
@ColumnInfo(name = "album_id")
|
@ColumnInfo(name = "album_id")
|
||||||
val albumId: Int,
|
val albumId: Long,
|
||||||
@ColumnInfo(name = "album_name")
|
@ColumnInfo(name = "album_name")
|
||||||
val albumName: String,
|
val albumName: String,
|
||||||
@ColumnInfo(name = "artist_id")
|
@ColumnInfo(name = "artist_id")
|
||||||
val artistId: Int,
|
val artistId: Long,
|
||||||
@ColumnInfo(name = "artist_name")
|
@ColumnInfo(name = "artist_name")
|
||||||
val artistName: String,
|
val artistName: String,
|
||||||
val composer: String?,
|
val composer: String?,
|
||||||
@ColumnInfo(name = "album_artist")
|
@ColumnInfo(name = "album_artist")
|
||||||
val albumArtist: String?
|
val albumArtist: String?
|
||||||
) : Parcelable {
|
) : Parcelable
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
@ColumnInfo(name = "song_key")
|
|
||||||
var songPrimaryKey: Long = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -8,83 +8,121 @@ fun List<SongEntity>.toSongs(): List<Song> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<Song>.toSongs(playlistId: Int): List<SongEntity> {
|
fun List<Song>.toSongs(playlistId: Long): List<SongEntity> {
|
||||||
return map {
|
return map {
|
||||||
it.toSongEntity(playlistId)
|
it.toSongEntity(playlistId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
fun SongEntity.toSong(): Song {
|
||||||
return Song(
|
return Song(
|
||||||
id,
|
id = id,
|
||||||
title,
|
title = title,
|
||||||
trackNumber,
|
trackNumber = trackNumber,
|
||||||
year,
|
year = year,
|
||||||
duration,
|
duration = duration,
|
||||||
data,
|
data = data,
|
||||||
dateModified,
|
dateModified = dateModified,
|
||||||
albumId,
|
albumId = albumId,
|
||||||
albumName,
|
albumName = albumName,
|
||||||
artistId,
|
artistId = artistId,
|
||||||
artistName,
|
artistName = artistName,
|
||||||
composer,
|
composer = composer,
|
||||||
albumArtist
|
albumArtist = albumArtist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PlayCountEntity.toSong(): Song {
|
fun PlayCountEntity.toSong(): Song {
|
||||||
return Song(
|
return Song(
|
||||||
id,
|
id = id,
|
||||||
title,
|
title = title,
|
||||||
trackNumber,
|
trackNumber = trackNumber,
|
||||||
year,
|
year = year,
|
||||||
duration,
|
duration = duration,
|
||||||
data,
|
data = data,
|
||||||
dateModified,
|
dateModified = dateModified,
|
||||||
albumId,
|
albumId = albumId,
|
||||||
albumName,
|
albumName = albumName,
|
||||||
artistId,
|
artistId = artistId,
|
||||||
artistName,
|
artistName = artistName,
|
||||||
composer,
|
composer = composer,
|
||||||
albumArtist
|
albumArtist = albumArtist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun HistoryEntity.toSong(): Song {
|
fun HistoryEntity.toSong(): Song {
|
||||||
return Song(
|
return Song(
|
||||||
id,
|
id = id,
|
||||||
title,
|
title = title,
|
||||||
trackNumber,
|
trackNumber = trackNumber,
|
||||||
year,
|
year = year,
|
||||||
duration,
|
duration = duration,
|
||||||
data,
|
data = data,
|
||||||
dateModified,
|
dateModified = dateModified,
|
||||||
albumId,
|
albumId = albumId,
|
||||||
albumName,
|
albumName = albumName,
|
||||||
artistId,
|
artistId = artistId,
|
||||||
artistName,
|
artistName = artistName,
|
||||||
composer,
|
composer = composer,
|
||||||
albumArtist
|
albumArtist = albumArtist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Song.toPlayCount(): PlayCountEntity {
|
fun Song.toPlayCount(): PlayCountEntity {
|
||||||
return PlayCountEntity(
|
return PlayCountEntity(
|
||||||
id,
|
id = id,
|
||||||
title,
|
title = title,
|
||||||
trackNumber,
|
trackNumber = trackNumber,
|
||||||
year,
|
year = year,
|
||||||
duration,
|
duration = duration,
|
||||||
data,
|
data = data,
|
||||||
dateModified,
|
dateModified = dateModified,
|
||||||
albumId,
|
albumId = albumId,
|
||||||
albumName,
|
albumName = albumName,
|
||||||
artistId,
|
artistId = artistId,
|
||||||
artistName,
|
artistName = artistName,
|
||||||
composer,
|
composer = composer,
|
||||||
albumArtist,
|
albumArtist = albumArtist,
|
||||||
System.currentTimeMillis(),
|
timePlayed = System.currentTimeMillis(),
|
||||||
1
|
playCount = 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.EXTRA_SONG
|
import code.name.monkey.retromusic.EXTRA_SONG
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
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.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extra
|
import code.name.monkey.retromusic.extensions.extra
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
@ -56,8 +57,8 @@ class CreatePlaylistDialog : DialogFragment() {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
|
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
|
||||||
val playlistId: Long =
|
val playlistId: Long =
|
||||||
libraryViewModel.createPlaylist(PlaylistEntity(playlistName))
|
libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlistName))
|
||||||
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) })
|
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) })
|
||||||
libraryViewModel.forceReload(Playlists)
|
libraryViewModel.forceReload(Playlists)
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,10 @@ package code.name.monkey.retromusic.fragments
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -160,11 +163,21 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
|
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
|
||||||
|
|
||||||
|
|
||||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
override fun onArtist(artistId: Long, imageView: ImageView) {
|
||||||
|
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))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,10 +5,7 @@ import code.name.monkey.retromusic.RECENT_ALBUMS
|
||||||
import code.name.monkey.retromusic.RECENT_ARTISTS
|
import code.name.monkey.retromusic.RECENT_ARTISTS
|
||||||
import code.name.monkey.retromusic.TOP_ALBUMS
|
import code.name.monkey.retromusic.TOP_ALBUMS
|
||||||
import code.name.monkey.retromusic.TOP_ARTISTS
|
import code.name.monkey.retromusic.TOP_ARTISTS
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.*
|
||||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
|
||||||
import code.name.monkey.retromusic.db.toSong
|
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType.*
|
import code.name.monkey.retromusic.fragments.ReloadType.*
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
|
@ -82,7 +79,6 @@ class LibraryViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHome(): LiveData<List<Home>> {
|
fun getHome(): LiveData<List<Home>> {
|
||||||
fetchHomeSections()
|
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +181,7 @@ class LibraryViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renameRoomPlaylist(playListId: Int, name: String) = viewModelScope.launch(IO) {
|
fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
|
||||||
repository.renameRoomPlaylist(playListId, name)
|
repository.renameRoomPlaylist(playListId, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +197,8 @@ class LibraryViewModel(
|
||||||
repository.deleteRoomPlaylist(playlists)
|
repository.deleteRoomPlaylist(playlists)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun albumById(id: Int) = repository.albumById(id)
|
suspend fun albumById(id: Long) = repository.albumById(id)
|
||||||
suspend fun artistById(id: Int) = repository.artistById(id)
|
suspend fun artistById(id: Long) = repository.artistById(id)
|
||||||
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
||||||
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
||||||
suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs)
|
suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs)
|
||||||
|
@ -225,9 +221,9 @@ class LibraryViewModel(
|
||||||
}
|
}
|
||||||
repository.insertSongs(songEntities)
|
repository.insertSongs(songEntities)
|
||||||
} else {
|
} else {
|
||||||
val playListId = createPlaylist(PlaylistEntity(playlist.name))
|
val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name))
|
||||||
val songEntities = playlist.getSongs().map {
|
val songEntities = playlist.getSongs().map {
|
||||||
it.toSongEntity(playListId.toInt())
|
it.toSongEntity(playListId)
|
||||||
}
|
}
|
||||||
repository.insertSongs(songEntities)
|
repository.insertSongs(songEntities)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.core.text.HtmlCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
|
@ -48,6 +49,8 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
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_content.*
|
||||||
import kotlinx.android.synthetic.main.fragment_album_details.*
|
import kotlinx.android.synthetic.main.fragment_album_details.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -74,8 +77,16 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
private val savedSortOrder: String
|
private val savedSortOrder: String
|
||||||
get() = PreferenceUtil.albumDetailSongSortOrder
|
get() = PreferenceUtil.albumDetailSongSortOrder
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
sharedElementEnterTransition = MaterialContainerTransform().apply {
|
||||||
|
duration = 1000L
|
||||||
|
pathMotion = MaterialArcMotion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
libraryViewModel.setPanelState(NowPlayingPanelState.COLLAPSED_WITHOUT)
|
libraryViewModel.setPanelState(NowPlayingPanelState.COLLAPSED_WITHOUT)
|
||||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||||
|
@ -95,11 +106,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
bundleOf(EXTRA_ARTIST_ID to album.artistId)
|
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 {
|
shuffleAction.setOnClickListener {
|
||||||
MusicPlayerRemote.openAndShuffleQueue(
|
MusicPlayerRemote.openAndShuffleQueue(
|
||||||
album.songs!!,
|
album.songs,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +149,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAlbum(album: Album) {
|
private fun showAlbum(album: Album) {
|
||||||
if (album.songs!!.isEmpty()) {
|
if (album.songs.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.album = album
|
this.album = album
|
||||||
|
@ -258,10 +269,12 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
playAction.applyOutlineColor(color)
|
playAction.applyOutlineColor(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Long, view: View) {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to albumId)
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
|
null,
|
||||||
|
FragmentNavigatorExtras(view to getString(R.string.transition_album_art))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,29 +366,31 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
|
|
||||||
private fun setSaveSortOrder(sortOrder: String) {
|
private fun setSaveSortOrder(sortOrder: String) {
|
||||||
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
||||||
when (sortOrder) {
|
val songs = when (sortOrder) {
|
||||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
|
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
|
||||||
o1.trackNumber.compareTo(
|
o1.trackNumber.compareTo(
|
||||||
o2.trackNumber
|
o2.trackNumber
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
|
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||||
o1.title.compareTo(
|
o1.title.compareTo(
|
||||||
o2.title
|
o2.title
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
|
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||||
o2.title.compareTo(
|
o2.title.compareTo(
|
||||||
o1.title
|
o1.title
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||||
o1.duration.compareTo(
|
o1.duration.compareTo(
|
||||||
o2.duration
|
o2.duration
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
album.songs?.let { simpleSongAdapter.swapDataSet(it) }
|
else -> throw IllegalArgumentException("invalid $sortOrder")
|
||||||
|
}
|
||||||
|
album = album.copy(songs = songs)
|
||||||
|
simpleSongAdapter.swapDataSet(album.songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -13,14 +13,14 @@ import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
|
||||||
class AlbumDetailsViewModel(
|
class AlbumDetailsViewModel(
|
||||||
private val repository: RealRepository,
|
private val repository: RealRepository,
|
||||||
private val albumId: Int
|
private val albumId: Long
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
||||||
emit(repository.albumByIdAsync(albumId))
|
emit(repository.albumByIdAsync(albumId))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getArtist(artistId: Int): LiveData<Artist> = liveData(IO) {
|
fun getArtist(artistId: Long): LiveData<Artist> = liveData(IO) {
|
||||||
val artist = repository.artistById(artistId)
|
val artist = repository.artistById(artistId)
|
||||||
emit(artist)
|
emit(artist)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class AlbumDetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) {
|
fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) {
|
||||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
artist.albums.filter { item -> item.id != albumId }.let { albums ->
|
||||||
if (albums.isNotEmpty()) emit(albums)
|
if (albums.isNotEmpty()) emit(albums)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,17 @@ import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
|
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||||
|
|
||||||
|
|
||||||
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||||
AlbumClickListener {
|
AlbumClickListener {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialFadeThrough()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer {
|
||||||
|
@ -43,7 +49,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
return AlbumAdapter(
|
return AlbumAdapter(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
R.layout.item_grid,
|
itemLayoutRes(),
|
||||||
null,
|
null,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -97,7 +103,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Long, view: View) {
|
||||||
findActivityNavController(R.id.fragment_container).navigate(
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
|
@ -285,5 +291,5 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AlbumClickListener {
|
interface AlbumClickListener {
|
||||||
fun onAlbumClick(albumId: Int, view: View)
|
fun onAlbumClick(albumId: Long, view: View)
|
||||||
}
|
}
|
|
@ -17,7 +17,6 @@ import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
|
||||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
||||||
|
@ -40,7 +39,6 @@ import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.state.NowPlayingPanelState
|
import code.name.monkey.retromusic.state.NowPlayingPanelState
|
||||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||||
|
@ -202,14 +200,12 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(color: Int) {
|
private fun setColors(color: Int) {
|
||||||
val finalColor = if (PreferenceUtil.isAdaptiveColor) color
|
shuffleAction.applyColor(color)
|
||||||
else ThemeStore.accentColor(requireContext())
|
playAction.applyOutlineColor(color)
|
||||||
shuffleAction.applyColor(finalColor)
|
|
||||||
playAction.applyOutlineColor(finalColor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Long, view: View) {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
|
|
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
|
||||||
class ArtistDetailsViewModel(
|
class ArtistDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private val artistId: Int
|
private val artistId: Long
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
fun getArtist(): LiveData<Artist> = liveData(IO) {
|
fun getArtist(): LiveData<Artist> = liveData(IO) {
|
||||||
|
|
|
@ -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.helper.SortOrder.ArtistSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||||
|
|
||||||
|
|
||||||
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||||
ArtistClickListener {
|
ArtistClickListener {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialFadeThrough()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -46,7 +51,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
return ArtistAdapter(
|
return ArtistAdapter(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
R.layout.item_grid_circle,
|
itemLayoutRes(),
|
||||||
null,
|
null,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -96,7 +101,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
override fun onArtist(artistId: Long, imageView: ImageView) {
|
||||||
val controller = findActivityNavController(R.id.fragment_container)
|
val controller = findActivityNavController(R.id.fragment_container)
|
||||||
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
||||||
}
|
}
|
||||||
|
@ -258,5 +263,5 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ArtistClickListener {
|
interface ArtistClickListener {
|
||||||
fun onArtist(artistId: Int, imageView: ImageView)
|
fun onArtist(artistId: Long, imageView: ImageView)
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@ import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||||
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
|
import code.name.monkey.retromusic.db.toSongEntity
|
||||||
import code.name.monkey.retromusic.dialogs.*
|
import code.name.monkey.retromusic.dialogs.*
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.whichFragment
|
import code.name.monkey.retromusic.extensions.whichFragment
|
||||||
|
|
|
@ -21,8 +21,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
|
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||||
|
|
||||||
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
|
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialFadeThrough()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
|
@ -36,6 +36,7 @@ import code.name.monkey.retromusic.glide.UserProfileGlideRequest
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import com.bumptech.glide.Glide
|
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.abs_playlists.*
|
||||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||||
import kotlinx.android.synthetic.main.home_content.*
|
import kotlinx.android.synthetic.main.home_content.*
|
||||||
|
@ -43,6 +44,10 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class HomeFragment :
|
class HomeFragment :
|
||||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
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()
|
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,16 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
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.hide
|
||||||
import code.name.monkey.retromusic.extensions.ripAlpha
|
import code.name.monkey.retromusic.extensions.ripAlpha
|
||||||
import code.name.monkey.retromusic.extensions.show
|
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.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.ViewUtil
|
import code.name.monkey.retromusic.util.ViewUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
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.animator.DraggableItemAnimator
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
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_controls.*
|
||||||
import kotlinx.android.synthetic.main.fragment_gradient_player.*
|
import kotlinx.android.synthetic.main.fragment_gradient_player.*
|
||||||
import kotlinx.android.synthetic.main.status_bar.*
|
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),
|
class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player),
|
||||||
MusicProgressViewUpdateHelper.Callback,
|
MusicProgressViewUpdateHelper.Callback,
|
||||||
|
@ -61,7 +68,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
||||||
private lateinit var linearLayoutManager: LinearLayoutManager
|
private lateinit var linearLayoutManager: LinearLayoutManager
|
||||||
|
|
||||||
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
private val bottomSheetCallbackList = object : BottomSheetCallback() {
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
playerQueueSheet.setPadding(
|
playerQueueSheet.setPadding(
|
||||||
|
@ -74,11 +81,11 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
when (newState) {
|
when (newState) {
|
||||||
BottomSheetBehavior.STATE_EXPANDED,
|
STATE_EXPANDED,
|
||||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
STATE_DRAGGING -> {
|
||||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
}
|
}
|
||||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
STATE_COLLAPSED -> {
|
||||||
resetToCurrentPosition()
|
resetToCurrentPosition()
|
||||||
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||||
}
|
}
|
||||||
|
@ -167,9 +174,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
override fun onBackPressed(): Boolean {
|
||||||
var wasExpanded = false
|
var wasExpanded = false
|
||||||
if (getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED) {
|
if (getQueuePanel().state == STATE_EXPANDED) {
|
||||||
wasExpanded = getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED
|
wasExpanded = getQueuePanel().state == STATE_EXPANDED
|
||||||
getQueuePanel().state = BottomSheetBehavior.STATE_COLLAPSED
|
getQueuePanel().state = STATE_COLLAPSED
|
||||||
return wasExpanded
|
return wasExpanded
|
||||||
}
|
}
|
||||||
return wasExpanded
|
return wasExpanded
|
||||||
|
@ -216,7 +223,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
override fun toggleFavorite(song: Song) {
|
override fun toggleFavorite(song: Song) {
|
||||||
super.toggleFavorite(song)
|
super.toggleFavorite(song)
|
||||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||||
updateIsFavorite()
|
updateIsFavoriteIcon()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +231,23 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
toggleFavorite(MusicPlayerRemote.currentSong)
|
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() {
|
private fun hideVolumeIfAvailable() {
|
||||||
if (PreferenceUtil.isVolumeVisibilityMode) {
|
if (PreferenceUtil.isVolumeVisibilityMode) {
|
||||||
childFragmentManager.beginTransaction()
|
childFragmentManager.beginTransaction()
|
||||||
|
@ -241,6 +265,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
updatePlayPauseDrawableState()
|
updatePlayPauseDrawableState()
|
||||||
updatePlayPauseDrawableState()
|
updatePlayPauseDrawableState()
|
||||||
updateQueue()
|
updateQueue()
|
||||||
|
updateIsFavoriteIcon()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayStateChanged() {
|
override fun onPlayStateChanged() {
|
||||||
|
@ -259,6 +284,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
super.onPlayingMetaChanged()
|
super.onPlayingMetaChanged()
|
||||||
updateSong()
|
updateSong()
|
||||||
updateQueuePosition()
|
updateQueuePosition()
|
||||||
|
updateIsFavoriteIcon()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueueChanged() {
|
override fun onQueueChanged() {
|
||||||
|
@ -359,13 +385,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
private fun updateLabel() {
|
private fun updateLabel() {
|
||||||
(MusicPlayerRemote.playingQueue.size - 1).apply {
|
(MusicPlayerRemote.playingQueue.size - 1).apply {
|
||||||
if (this == (MusicPlayerRemote.position)) {
|
if (this == (MusicPlayerRemote.position)) {
|
||||||
nextSong.hide()
|
nextSong.text = "Last song"
|
||||||
} else {
|
} else {
|
||||||
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
||||||
nextSong.apply {
|
nextSong.text = title
|
||||||
text = title
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,12 +483,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
|
|
||||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||||
progressSlider.max = total
|
progressSlider.max = total
|
||||||
|
|
||||||
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
|
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
|
||||||
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
|
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
|
||||||
animator.interpolator = LinearInterpolator()
|
animator.interpolator = LinearInterpolator()
|
||||||
animator.start()
|
animator.start()
|
||||||
|
|
||||||
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
||||||
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, LinearLayoutManager>(),
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,9 +11,14 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
|
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||||
import kotlinx.android.synthetic.main.fragment_library.*
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
|
|
||||||
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
|
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialFadeThrough()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
|
@ -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.helper.SortOrder.SongSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||||
|
|
||||||
|
|
||||||
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>() {
|
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialFadeThrough()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
|
@ -7,8 +7,8 @@ import org.koin.core.KoinComponent
|
||||||
import org.koin.core.inject
|
import org.koin.core.inject
|
||||||
|
|
||||||
abstract class AbsCustomPlaylist(
|
abstract class AbsCustomPlaylist(
|
||||||
id: Int = -1,
|
id: Long,
|
||||||
name: String = ""
|
name: String
|
||||||
) : Playlist(id, name), KoinComponent {
|
) : Playlist(id, name), KoinComponent {
|
||||||
|
|
||||||
abstract fun songs(): List<Song>
|
abstract fun songs(): List<Song>
|
||||||
|
|
|
@ -14,19 +14,15 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.model
|
package code.name.monkey.retromusic.model
|
||||||
|
|
||||||
import java.util.*
|
data class Album(
|
||||||
|
val id: Long,
|
||||||
class Album {
|
val songs: List<Song>
|
||||||
|
) {
|
||||||
val songs: ArrayList<Song>?
|
|
||||||
|
|
||||||
val id: Int
|
|
||||||
get() = safeGetFirstSong().albumId
|
|
||||||
|
|
||||||
val title: String?
|
val title: String?
|
||||||
get() = safeGetFirstSong().albumName
|
get() = safeGetFirstSong().albumName
|
||||||
|
|
||||||
val artistId: Int
|
val artistId: Long
|
||||||
get() = safeGetFirstSong().artistId
|
get() = safeGetFirstSong().artistId
|
||||||
|
|
||||||
val artistName: String?
|
val artistName: String?
|
||||||
|
@ -39,20 +35,17 @@ class Album {
|
||||||
get() = safeGetFirstSong().dateModified
|
get() = safeGetFirstSong().dateModified
|
||||||
|
|
||||||
val songCount: Int
|
val songCount: Int
|
||||||
get() = songs!!.size
|
get() = songs.size
|
||||||
|
|
||||||
val albumArtist: String?
|
val albumArtist: String?
|
||||||
get() = safeGetFirstSong().albumArtist
|
get() = safeGetFirstSong().albumArtist
|
||||||
|
|
||||||
constructor(songs: ArrayList<Song>) {
|
|
||||||
this.songs = songs
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.songs = ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun safeGetFirstSong(): Song {
|
fun safeGetFirstSong(): Song {
|
||||||
return if (songs!!.isEmpty()) Song.emptySong else songs[0]
|
return songs.firstOrNull() ?: Song.emptySong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val empty = Album(-1, emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,10 @@ package code.name.monkey.retromusic.model
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class Artist {
|
data class Artist(
|
||||||
val albums: ArrayList<Album>?
|
val id: Long,
|
||||||
|
val albums: List<Album>
|
||||||
val id: Int
|
) {
|
||||||
get() = safeGetFirstAlbum().artistId
|
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
get() {
|
get() {
|
||||||
|
@ -34,37 +33,25 @@ class Artist {
|
||||||
val songCount: Int
|
val songCount: Int
|
||||||
get() {
|
get() {
|
||||||
var songCount = 0
|
var songCount = 0
|
||||||
for (album in albums!!) {
|
for (album in albums) {
|
||||||
songCount += album.songCount
|
songCount += album.songCount
|
||||||
}
|
}
|
||||||
return songCount
|
return songCount
|
||||||
}
|
}
|
||||||
|
|
||||||
val albumCount: Int
|
val albumCount: Int
|
||||||
get() = albums!!.size
|
get() = albums.size
|
||||||
|
|
||||||
val songs: ArrayList<Song>
|
val songs: List<Song>
|
||||||
get() {
|
get() = albums.flatMap { it.songs }
|
||||||
val songs = ArrayList<Song>()
|
|
||||||
for (album in albums!!) {
|
|
||||||
songs.addAll(album.songs!!)
|
|
||||||
}
|
|
||||||
return songs
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(albums: ArrayList<Album>) {
|
|
||||||
this.albums = albums
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.albums = ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun safeGetFirstAlbum(): Album {
|
fun safeGetFirstAlbum(): Album {
|
||||||
return if (albums!!.isEmpty()) Album() else albums[0]
|
return albums.firstOrNull() ?: Album.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
|
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
|
||||||
|
val empty = Artist(-1, emptyList())
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.model;
|
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
|
|
||||||
|
|
||||||
public class CategoryInfo implements Parcelable {
|
|
||||||
|
|
||||||
public static final Creator<CategoryInfo> CREATOR = new Creator<CategoryInfo>() {
|
|
||||||
public CategoryInfo createFromParcel(Parcel source) {
|
|
||||||
return new CategoryInfo(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CategoryInfo[] newArray(int size) {
|
|
||||||
return new CategoryInfo[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public Category category;
|
|
||||||
public boolean visible;
|
|
||||||
|
|
||||||
public CategoryInfo(Category category, boolean visible) {
|
|
||||||
this.category = category;
|
|
||||||
this.visible = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private CategoryInfo(Parcel source) {
|
|
||||||
category = (Category) source.readSerializable();
|
|
||||||
visible = source.readInt() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
dest.writeSerializable(category);
|
|
||||||
dest.writeInt(visible ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Category {
|
|
||||||
Home(R.id.action_home, R.string.for_you, R.drawable.ic_face),
|
|
||||||
Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack),
|
|
||||||
Albums(R.id.action_album, R.string.albums, R.drawable.ic_album),
|
|
||||||
Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist),
|
|
||||||
Playlists(R.id.action_playlist, R.string.playlists, (R.drawable.ic_queue_music)),
|
|
||||||
Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar),
|
|
||||||
Folder(R.id.action_folder, R.string.folders, R.drawable.ic_folder);
|
|
||||||
|
|
||||||
public final int icon;
|
|
||||||
|
|
||||||
public final int id;
|
|
||||||
|
|
||||||
public final int stringRes;
|
|
||||||
|
|
||||||
Category(int id, @StringRes int stringRes, @DrawableRes int icon) {
|
|
||||||
this.stringRes = stringRes;
|
|
||||||
this.id = id;
|
|
||||||
this.icon = icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,8 +16,10 @@ package code.name.monkey.retromusic.model
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
class Contributor(
|
data class Contributor(
|
||||||
val name: String,
|
val name: String,
|
||||||
val summary: String,
|
val summary: String,
|
||||||
val link: String, @SerializedName("profile_image") val profileImage: String
|
val link: String,
|
||||||
|
@SerializedName("profile_image")
|
||||||
|
val profileImage: String
|
||||||
)
|
)
|
|
@ -18,4 +18,8 @@ import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Genre(val id: Int = -1, val name: String, val songCount: Int) : Parcelable
|
data class Genre(
|
||||||
|
val id: Long,
|
||||||
|
val name: String,
|
||||||
|
val songCount: Int
|
||||||
|
) : Parcelable
|
|
@ -17,7 +17,7 @@ package code.name.monkey.retromusic.model
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import code.name.monkey.retromusic.HomeSection
|
import code.name.monkey.retromusic.HomeSection
|
||||||
|
|
||||||
class Home(
|
data class Home(
|
||||||
val arrayList: List<Any>,
|
val arrayList: List<Any>,
|
||||||
@HomeSection
|
@HomeSection
|
||||||
val homeSection: Int,
|
val homeSection: Int,
|
||||||
|
|
|
@ -10,10 +10,14 @@ import org.koin.core.get
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
open class Playlist(
|
open class Playlist(
|
||||||
val id: Int = -1,
|
val id: Long,
|
||||||
val name: String = ""
|
val name: String
|
||||||
) : Parcelable, KoinComponent {
|
) : Parcelable, KoinComponent {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val empty = Playlist(-1, "")
|
||||||
|
}
|
||||||
|
|
||||||
// this default implementation covers static playlists
|
// this default implementation covers static playlists
|
||||||
fun getSongs(): List<Song> {
|
fun getSongs(): List<Song> {
|
||||||
return RealPlaylistRepository(get()).playlistSongs(id)
|
return RealPlaylistRepository(get()).playlistSongs(id)
|
||||||
|
@ -27,4 +31,24 @@ open class Playlist(
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Playlist
|
||||||
|
|
||||||
|
if (id != other.id) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = id.hashCode()
|
||||||
|
result = 31 * result + name.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,58 +18,64 @@ import code.name.monkey.retromusic.db.HistoryEntity
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
|
// update equals and hashcode if fields changes
|
||||||
@Parcelize
|
@Parcelize
|
||||||
open class Song(
|
open class Song(
|
||||||
val id: Int,
|
open val id: Long,
|
||||||
val title: String,
|
open val title: String,
|
||||||
val trackNumber: Int,
|
open val trackNumber: Int,
|
||||||
val year: Int,
|
open val year: Int,
|
||||||
val duration: Long,
|
open val duration: Long,
|
||||||
val data: String,
|
open val data: String,
|
||||||
val dateModified: Long,
|
open val dateModified: Long,
|
||||||
val albumId: Int,
|
open val albumId: Long,
|
||||||
val albumName: String,
|
open val albumName: String,
|
||||||
val artistId: Int,
|
open val artistId: Long,
|
||||||
val artistName: String,
|
open val artistName: String,
|
||||||
val composer: String?,
|
open val composer: String?,
|
||||||
val albumArtist: String?
|
open val albumArtist: String?
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
fun toHistoryEntity(timePlayed: Long): HistoryEntity {
|
|
||||||
return HistoryEntity(
|
|
||||||
id,
|
// need to override manually because is open and cannot be a data class
|
||||||
title,
|
override fun equals(other: Any?): Boolean {
|
||||||
trackNumber,
|
if (this === other) return true
|
||||||
year,
|
if (javaClass != other?.javaClass) return false
|
||||||
duration,
|
|
||||||
data,
|
other as Song
|
||||||
dateModified,
|
|
||||||
albumId,
|
if (id != other.id) return false
|
||||||
albumName,
|
if (title != other.title) return false
|
||||||
artistId,
|
if (trackNumber != other.trackNumber) return false
|
||||||
artistName,
|
if (year != other.year) return false
|
||||||
composer,
|
if (duration != other.duration) return false
|
||||||
albumArtist,
|
if (data != other.data) return false
|
||||||
timePlayed
|
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 {
|
override fun hashCode(): Int {
|
||||||
return SongEntity(
|
var result = id.hashCode()
|
||||||
playListId,
|
result = 31 * result + title.hashCode()
|
||||||
id,
|
result = 31 * result + trackNumber
|
||||||
title,
|
result = 31 * result + year
|
||||||
trackNumber,
|
result = 31 * result + duration.hashCode()
|
||||||
year,
|
result = 31 * result + data.hashCode()
|
||||||
duration,
|
result = 31 * result + dateModified.hashCode()
|
||||||
data,
|
result = 31 * result + albumId.hashCode()
|
||||||
dateModified,
|
result = 31 * result + albumName.hashCode()
|
||||||
albumId,
|
result = 31 * result + artistId.hashCode()
|
||||||
albumName,
|
result = 31 * result + artistName.hashCode()
|
||||||
artistId,
|
result = 31 * result + (composer?.hashCode() ?: 0)
|
||||||
artistName,
|
result = 31 * result + (albumArtist?.hashCode() ?: 0)
|
||||||
composer,
|
return result
|
||||||
albumArtist
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,19 +83,19 @@ open class Song(
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val emptySong = Song(
|
val emptySong = Song(
|
||||||
-1,
|
id = -1,
|
||||||
"",
|
title = "",
|
||||||
-1,
|
trackNumber = -1,
|
||||||
-1,
|
year = -1,
|
||||||
-1,
|
duration = -1,
|
||||||
"",
|
data = "",
|
||||||
-1,
|
dateModified = -1,
|
||||||
-1,
|
albumId = -1,
|
||||||
"",
|
albumName = "",
|
||||||
-1,
|
artistId = -1,
|
||||||
"",
|
artistName = "",
|
||||||
"",
|
composer = "",
|
||||||
""
|
albumArtist = ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,9 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||||
|
|
||||||
abstract class AbsSmartPlaylist(
|
abstract class AbsSmartPlaylist(
|
||||||
name: String = "",
|
name: String,
|
||||||
@DrawableRes val iconRes: Int = R.drawable.ic_queue_music
|
@DrawableRes val iconRes: Int = R.drawable.ic_queue_music
|
||||||
) : AbsCustomPlaylist(-Math.abs(31 * name.hashCode() + iconRes * name.hashCode() * 31 * 31), name)
|
) : AbsCustomPlaylist(
|
||||||
|
id = PlaylistIdGenerator(name, iconRes),
|
||||||
|
name = name
|
||||||
|
)
|
|
@ -7,12 +7,11 @@ import kotlinx.android.parcel.Parcelize
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class HistoryPlaylist :
|
class HistoryPlaylist : AbsSmartPlaylist(
|
||||||
AbsSmartPlaylist(
|
name = App.getContext().getString(R.string.history),
|
||||||
App.getContext().getString(R.string.history),
|
iconRes = R.drawable.ic_history
|
||||||
R.drawable.ic_history
|
), KoinComponent {
|
||||||
),
|
|
||||||
KoinComponent {
|
|
||||||
override fun songs(): List<Song> {
|
override fun songs(): List<Song> {
|
||||||
return topPlayedRepository.recentlyPlayedTracks()
|
return topPlayedRepository.recentlyPlayedTracks()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,10 @@ import code.name.monkey.retromusic.model.Song
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class LastAddedPlaylist :
|
class LastAddedPlaylist : AbsSmartPlaylist(
|
||||||
AbsSmartPlaylist(App.getContext().getString(R.string.last_added), R.drawable.ic_library_add) {
|
name = App.getContext().getString(R.string.last_added),
|
||||||
|
iconRes = R.drawable.ic_library_add
|
||||||
|
) {
|
||||||
override fun songs(): List<Song> {
|
override fun songs(): List<Song> {
|
||||||
return lastAddedRepository.recentSongs()
|
return lastAddedRepository.recentSongs()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class NotPlayedPlaylist : AbsSmartPlaylist(
|
class NotPlayedPlaylist : AbsSmartPlaylist(
|
||||||
App.getContext().getString(R.string.not_recently_played),
|
name = App.getContext().getString(R.string.not_recently_played),
|
||||||
R.drawable.ic_watch_later
|
iconRes = R.drawable.ic_watch_later
|
||||||
) {
|
) {
|
||||||
override fun songs(): List<Song> {
|
override fun songs(): List<Song> {
|
||||||
return topPlayedRepository.notRecentlyPlayedTracks()
|
return topPlayedRepository.notRecentlyPlayedTracks()
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class ShuffleAllPlaylist : AbsSmartPlaylist(
|
class ShuffleAllPlaylist : AbsSmartPlaylist(
|
||||||
App.getContext().getString(R.string.action_shuffle_all),
|
name = App.getContext().getString(R.string.action_shuffle_all),
|
||||||
R.drawable.ic_shuffle
|
iconRes = R.drawable.ic_shuffle
|
||||||
) {
|
) {
|
||||||
override fun songs(): List<Song> {
|
override fun songs(): List<Song> {
|
||||||
return songRepository.songs()
|
return songRepository.songs()
|
||||||
|
|
|
@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class TopTracksPlaylist : AbsSmartPlaylist(
|
class TopTracksPlaylist : AbsSmartPlaylist(
|
||||||
App.getContext().getString(R.string.my_top_tracks),
|
name = App.getContext().getString(R.string.my_top_tracks),
|
||||||
R.drawable.ic_trending_up
|
iconRes = R.drawable.ic_trending_up
|
||||||
) {
|
) {
|
||||||
override fun songs(): List<Song> {
|
override fun songs(): List<Song> {
|
||||||
return topPlayedRepository.topTracks()
|
return topPlayedRepository.topTracks()
|
||||||
|
|
|
@ -31,7 +31,7 @@ interface AlbumRepository {
|
||||||
|
|
||||||
fun albums(query: String): List<Album>
|
fun albums(query: String): List<Album>
|
||||||
|
|
||||||
fun album(albumId: Int): Album
|
fun album(albumId: Long): Album
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
||||||
|
@ -59,70 +59,42 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
||||||
return splitIntoAlbums(songs)
|
return splitIntoAlbums(songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun album(albumId: Int): Album {
|
override fun album(albumId: Long): Album {
|
||||||
val cursor = songRepository.makeSongCursor(
|
val cursor = songRepository.makeSongCursor(
|
||||||
AudioColumns.ALBUM_ID + "=?",
|
AudioColumns.ALBUM_ID + "=?",
|
||||||
arrayOf(albumId.toString()),
|
arrayOf(albumId.toString()),
|
||||||
getSongLoaderSortOrder()
|
getSongLoaderSortOrder()
|
||||||
)
|
)
|
||||||
val songs = songRepository.songs(cursor)
|
val songs = songRepository.songs(cursor)
|
||||||
val album = Album(ArrayList(songs))
|
val album = Album(albumId, songs)
|
||||||
sortAlbumSongs(album)
|
sortAlbumSongs(album)
|
||||||
return album
|
return album
|
||||||
}
|
}
|
||||||
|
|
||||||
fun splitIntoAlbums(
|
fun splitIntoAlbums(
|
||||||
songs: List<Song>?
|
songs: List<Song>
|
||||||
): List<Album> {
|
): List<Album> {
|
||||||
val albums = ArrayList<Album>()
|
return songs.groupBy { it.albumId }
|
||||||
if (songs != null) {
|
.map { sortAlbumSongs(Album(it.key, it.value)) }
|
||||||
for (song in songs) {
|
|
||||||
getOrCreateAlbum(albums, song.albumId).songs?.add(song)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (album in albums) {
|
|
||||||
sortAlbumSongs(album)
|
|
||||||
}
|
|
||||||
return albums
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrCreateAlbum(
|
private fun sortAlbumSongs(album: Album): Album {
|
||||||
albums: ArrayList<Album>,
|
val songs = when (PreferenceUtil.albumDetailSongSortOrder) {
|
||||||
albumId: Int
|
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
|
||||||
): Album {
|
o1.trackNumber.compareTo(o2.trackNumber)
|
||||||
for (album in albums) {
|
|
||||||
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) {
|
|
||||||
return album
|
|
||||||
}
|
}
|
||||||
|
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||||
|
o1.title.compareTo(o2.title)
|
||||||
}
|
}
|
||||||
val album = Album()
|
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||||
albums.add(album)
|
o2.title.compareTo(o1.title)
|
||||||
return album
|
|
||||||
}
|
}
|
||||||
|
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||||
private fun sortAlbumSongs(album: Album) {
|
o1.duration.compareTo(o2.duration)
|
||||||
when (PreferenceUtil.albumDetailSongSortOrder) {
|
|
||||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
|
|
||||||
o1.trackNumber.compareTo(
|
|
||||||
o2.trackNumber
|
|
||||||
)
|
|
||||||
})
|
|
||||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
|
|
||||||
o1.title.compareTo(
|
|
||||||
o2.title
|
|
||||||
)
|
|
||||||
})
|
|
||||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
|
|
||||||
o2.title.compareTo(
|
|
||||||
o1.title
|
|
||||||
)
|
|
||||||
})
|
|
||||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
|
||||||
o1.duration.compareTo(
|
|
||||||
o2.duration
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
else -> throw IllegalArgumentException("invalid ${PreferenceUtil.albumDetailSongSortOrder}")
|
||||||
|
}
|
||||||
|
return album.copy(songs = songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSongLoaderSortOrder(): String {
|
private fun getSongLoaderSortOrder(): String {
|
||||||
|
|
|
@ -26,7 +26,7 @@ interface ArtistRepository {
|
||||||
|
|
||||||
fun artists(query: String): List<Artist>
|
fun artists(query: String): List<Artist>
|
||||||
|
|
||||||
fun artist(artistId: Int): Artist
|
fun artist(artistId: Long): Artist
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealArtistRepository(
|
class RealArtistRepository(
|
||||||
|
@ -39,7 +39,16 @@ class RealArtistRepository(
|
||||||
PreferenceUtil.artistAlbumSortOrder + ", " +
|
PreferenceUtil.artistAlbumSortOrder + ", " +
|
||||||
PreferenceUtil.artistSongSortOrder
|
PreferenceUtil.artistSongSortOrder
|
||||||
}
|
}
|
||||||
|
override fun artist(artistId: Long): Artist {
|
||||||
|
val songs = songRepository.songs(
|
||||||
|
songRepository.makeSongCursor(
|
||||||
|
AudioColumns.ARTIST_ID + "=?",
|
||||||
|
arrayOf(artistId.toString()),
|
||||||
|
getSongLoaderSortOrder()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return Artist(artistId, albumRepository.splitIntoAlbums(songs))
|
||||||
|
}
|
||||||
override fun artists(): List<Artist> {
|
override fun artists(): List<Artist> {
|
||||||
val songs = songRepository.songs(
|
val songs = songRepository.songs(
|
||||||
songRepository.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
|
@ -50,17 +59,6 @@ class RealArtistRepository(
|
||||||
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun artists(query: String): List<Artist> {
|
|
||||||
val songs = songRepository.songs(
|
|
||||||
songRepository.makeSongCursor(
|
|
||||||
AudioColumns.ARTIST + " LIKE ?",
|
|
||||||
arrayOf("%$query%"),
|
|
||||||
getSongLoaderSortOrder()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun albumArtists(): List<Artist> {
|
override fun albumArtists(): List<Artist> {
|
||||||
val songs = songRepository.songs(
|
val songs = songRepository.songs(
|
||||||
songRepository.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
|
@ -72,49 +70,34 @@ class RealArtistRepository(
|
||||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun splitIntoAlbumArtists(albums: List<Album>): List<Artist> {
|
override fun artists(query: String): List<Artist> {
|
||||||
// First group the songs in albums by filtering each artist name
|
|
||||||
val amap = hashMapOf<String, Artist>()
|
|
||||||
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 {
|
|
||||||
val songs = songRepository.songs(
|
val songs = songRepository.songs(
|
||||||
songRepository.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
AudioColumns.ARTIST_ID + "=?",
|
AudioColumns.ARTIST + " LIKE ?",
|
||||||
arrayOf(artistId.toString()),
|
arrayOf("%$query%"),
|
||||||
getSongLoaderSortOrder()
|
getSongLoaderSortOrder()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return Artist(ArrayList(albumRepository.splitIntoAlbums(songs)))
|
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun splitIntoArtists(albums: List<Album>?): List<Artist> {
|
|
||||||
val artists = mutableListOf<Artist>()
|
private fun splitIntoAlbumArtists(albums: List<Album>): List<Artist> {
|
||||||
if (albums != null) {
|
return albums.groupBy { it.albumArtist }
|
||||||
for (album in albums) {
|
.map {
|
||||||
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
val currentAlbums = it.value
|
||||||
|
if (albums.isNotEmpty()) {
|
||||||
|
Artist(currentAlbums[0].id, currentAlbums)
|
||||||
|
} else {
|
||||||
|
Artist.empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return artists
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrCreateArtist(artists: MutableList<Artist>, artistId: Int): Artist {
|
|
||||||
for (artist in artists) {
|
|
||||||
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
|
fun splitIntoArtists(albums: List<Album>): List<Artist> {
|
||||||
return artist
|
return albums.groupBy { it.artistId }
|
||||||
}
|
.map { Artist(it.key, it.value) }
|
||||||
}
|
|
||||||
val album = Artist()
|
|
||||||
artists.add(album)
|
|
||||||
return album
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.Genres
|
import android.provider.MediaStore.Audio.Genres
|
||||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||||
import code.name.monkey.retromusic.Constants.baseProjection
|
import code.name.monkey.retromusic.Constants.baseProjection
|
||||||
|
import code.name.monkey.retromusic.extensions.getLong
|
||||||
|
import code.name.monkey.retromusic.extensions.getString
|
||||||
import code.name.monkey.retromusic.model.Genre
|
import code.name.monkey.retromusic.model.Genre
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
@ -29,7 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
interface GenreRepository {
|
interface GenreRepository {
|
||||||
fun genres(): List<Genre>
|
fun genres(): List<Genre>
|
||||||
|
|
||||||
fun songs(genreId: Int): List<Song>
|
fun songs(genreId: Long): List<Song>
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealGenreRepository(
|
class RealGenreRepository(
|
||||||
|
@ -41,25 +43,25 @@ class RealGenreRepository(
|
||||||
return getGenresFromCursor(makeGenreCursor())
|
return getGenresFromCursor(makeGenreCursor())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun songs(genreId: Int): List<Song> {
|
override fun songs(genreId: Long): List<Song> {
|
||||||
// The genres table only stores songs that have a genre specified,
|
// The genres table only stores songs that have a genre specified,
|
||||||
// so we need to get songs without a genre a different way.
|
// so we need to get songs without a genre a different way.
|
||||||
return if (genreId == -1) {
|
return if (genreId == -1L) {
|
||||||
getSongsWithNoGenre()
|
getSongsWithNoGenre()
|
||||||
} else songRepository.songs(makeGenreSongCursor(genreId))
|
} else songRepository.songs(makeGenreSongCursor(genreId))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGenreFromCursor(cursor: Cursor): Genre {
|
private fun getGenreFromCursor(cursor: Cursor): Genre {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(Genres._ID)
|
||||||
val name = cursor.getString(1)
|
val name = cursor.getString(Genres.NAME)
|
||||||
val songCount = songs(id).size
|
val songCount = songs(id).size
|
||||||
return Genre(id, name, songCount)
|
return Genre(id, name, songCount)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre {
|
private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(Genres._ID)
|
||||||
val name = cursor.getString(1)
|
val name = cursor.getString(Genres.NAME)
|
||||||
return Genre(id, name, -1)
|
return Genre(id, name, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,9 +93,9 @@ class RealGenreRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeGenreSongCursor(genreId: Int): Cursor? {
|
private fun makeGenreSongCursor(genreId: Long): Cursor? {
|
||||||
return contentResolver.query(
|
return contentResolver.query(
|
||||||
Genres.Members.getContentUri("external", genreId.toLong()),
|
Genres.Members.getContentUri("external", genreId),
|
||||||
baseProjection,
|
baseProjection,
|
||||||
IS_MUSIC,
|
IS_MUSIC,
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -18,8 +18,14 @@ import android.content.ContentResolver
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.BaseColumns
|
import android.provider.BaseColumns
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
import android.provider.MediaStore.Audio.Playlists.*
|
||||||
import android.provider.MediaStore.Audio.PlaylistsColumns
|
import android.provider.MediaStore.Audio.PlaylistsColumns
|
||||||
import code.name.monkey.retromusic.Constants
|
import code.name.monkey.retromusic.Constants
|
||||||
|
import code.name.monkey.retromusic.extensions.getInt
|
||||||
|
import code.name.monkey.retromusic.extensions.getLong
|
||||||
|
import code.name.monkey.retromusic.extensions.getString
|
||||||
|
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong
|
import code.name.monkey.retromusic.model.PlaylistSong
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
@ -40,11 +46,11 @@ interface PlaylistRepository {
|
||||||
|
|
||||||
fun favoritePlaylist(playlistName: String): List<Playlist>
|
fun favoritePlaylist(playlistName: String): List<Playlist>
|
||||||
|
|
||||||
fun deletePlaylist(playlistId: Int)
|
fun deletePlaylist(playlistId: Long)
|
||||||
|
|
||||||
fun playlist(playlistId: Int): Playlist
|
fun playlist(playlistId: Long): Playlist
|
||||||
|
|
||||||
fun playlistSongs(playlistId: Int): List<Song>
|
fun playlistSongs(playlistId: Long): List<Song>
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealPlaylistRepository(
|
class RealPlaylistRepository(
|
||||||
|
@ -52,19 +58,20 @@ class RealPlaylistRepository(
|
||||||
) : PlaylistRepository {
|
) : PlaylistRepository {
|
||||||
|
|
||||||
override fun playlist(cursor: Cursor?): Playlist {
|
override fun playlist(cursor: Cursor?): Playlist {
|
||||||
var playlist = Playlist()
|
return cursor.use {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor?.moveToFirst() == true) {
|
||||||
playlist = getPlaylistFromCursorImpl(cursor)
|
getPlaylistFromCursorImpl(cursor)
|
||||||
|
} else {
|
||||||
|
Playlist.empty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cursor?.close()
|
|
||||||
return playlist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playlist(playlistName: String): Playlist {
|
override fun playlist(playlistName: String): Playlist {
|
||||||
return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName)))
|
return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playlist(playlistId: Int): Playlist {
|
override fun playlist(playlistId: Long): Playlist {
|
||||||
return playlist(
|
return playlist(
|
||||||
makePlaylistCursor(
|
makePlaylistCursor(
|
||||||
BaseColumns._ID + "=?",
|
BaseColumns._ID + "=?",
|
||||||
|
@ -101,8 +108,8 @@ class RealPlaylistRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deletePlaylist(playlistId: Int) {
|
override fun deletePlaylist(playlistId: Long) {
|
||||||
val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI
|
val localUri = EXTERNAL_CONTENT_URI
|
||||||
val localStringBuilder = StringBuilder()
|
val localStringBuilder = StringBuilder()
|
||||||
localStringBuilder.append("_id IN (")
|
localStringBuilder.append("_id IN (")
|
||||||
localStringBuilder.append(playlistId)
|
localStringBuilder.append(playlistId)
|
||||||
|
@ -113,12 +120,12 @@ class RealPlaylistRepository(
|
||||||
private fun getPlaylistFromCursorImpl(
|
private fun getPlaylistFromCursorImpl(
|
||||||
cursor: Cursor
|
cursor: Cursor
|
||||||
): Playlist {
|
): Playlist {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(MediaStore.MediaColumns._ID)
|
||||||
val name = cursor.getString(1)
|
val name = cursor.getString(NAME)
|
||||||
return Playlist(id, name)
|
return Playlist(id, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playlistSongs(playlistId: Int): List<Song> {
|
override fun playlistSongs(playlistId: Long): List<Song> {
|
||||||
val songs = arrayListOf<Song>()
|
val songs = arrayListOf<Song>()
|
||||||
val cursor = makePlaylistSongCursor(playlistId)
|
val cursor = makePlaylistSongCursor(playlistId)
|
||||||
|
|
||||||
|
@ -131,21 +138,21 @@ class RealPlaylistRepository(
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong {
|
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(Members.AUDIO_ID)
|
||||||
val title = cursor.getString(1)
|
val title = cursor.getString(AudioColumns.TITLE)
|
||||||
val trackNumber = cursor.getInt(2)
|
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||||
val year = cursor.getInt(3)
|
val year = cursor.getInt(AudioColumns.YEAR)
|
||||||
val duration = cursor.getLong(4)
|
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||||
val data = cursor.getString(5)
|
val data = cursor.getString(AudioColumns.DATA)
|
||||||
val dateModified = cursor.getLong(6)
|
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||||
val albumId = cursor.getInt(7)
|
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||||
val albumName = cursor.getString(8)
|
val albumName = cursor.getString(AudioColumns.ALBUM)
|
||||||
val artistId = cursor.getInt(9)
|
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||||
val artistName = cursor.getString(10)
|
val artistName = cursor.getString(AudioColumns.ARTIST)
|
||||||
val idInPlaylist = cursor.getInt(11)
|
val idInPlaylist = cursor.getLong(Members._ID)
|
||||||
val composer = cursor.getString(12)
|
val composer = cursor.getStringOrNull(AudioColumns.COMPOSER)
|
||||||
val albumArtist = cursor.getString(13)
|
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||||
return PlaylistSong(
|
return PlaylistSong(
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
|
@ -160,7 +167,7 @@ class RealPlaylistRepository(
|
||||||
artistName,
|
artistName,
|
||||||
playlistId,
|
playlistId,
|
||||||
idInPlaylist,
|
idInPlaylist,
|
||||||
composer,
|
composer ?: "",
|
||||||
albumArtist
|
albumArtist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -170,37 +177,37 @@ class RealPlaylistRepository(
|
||||||
values: Array<String>?
|
values: Array<String>?
|
||||||
): Cursor? {
|
): Cursor? {
|
||||||
return contentResolver.query(
|
return contentResolver.query(
|
||||||
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
BaseColumns._ID, /* 0 */
|
BaseColumns._ID, /* 0 */
|
||||||
PlaylistsColumns.NAME /* 1 */
|
PlaylistsColumns.NAME /* 1 */
|
||||||
),
|
),
|
||||||
selection,
|
selection,
|
||||||
values,
|
values,
|
||||||
MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER
|
DEFAULT_SORT_ORDER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun makePlaylistSongCursor(playlistId: Int): Cursor? {
|
private fun makePlaylistSongCursor(playlistId: Long): Cursor? {
|
||||||
return contentResolver.query(
|
return contentResolver.query(
|
||||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()),
|
Members.getContentUri("external", playlistId),
|
||||||
arrayOf(
|
arrayOf(
|
||||||
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0
|
Members.AUDIO_ID, // 0
|
||||||
MediaStore.Audio.AudioColumns.TITLE, // 1
|
AudioColumns.TITLE, // 1
|
||||||
MediaStore.Audio.AudioColumns.TRACK, // 2
|
AudioColumns.TRACK, // 2
|
||||||
MediaStore.Audio.AudioColumns.YEAR, // 3
|
AudioColumns.YEAR, // 3
|
||||||
MediaStore.Audio.AudioColumns.DURATION, // 4
|
AudioColumns.DURATION, // 4
|
||||||
MediaStore.Audio.AudioColumns.DATA, // 5
|
AudioColumns.DATA, // 5
|
||||||
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
|
AudioColumns.DATE_MODIFIED, // 6
|
||||||
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
|
AudioColumns.ALBUM_ID, // 7
|
||||||
MediaStore.Audio.AudioColumns.ALBUM, // 8
|
AudioColumns.ALBUM, // 8
|
||||||
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
AudioColumns.ARTIST_ID, // 9
|
||||||
MediaStore.Audio.AudioColumns.ARTIST, // 10
|
AudioColumns.ARTIST, // 10
|
||||||
MediaStore.Audio.Playlists.Members._ID,//11
|
Members._ID,//11
|
||||||
MediaStore.Audio.AudioColumns.COMPOSER,//12
|
AudioColumns.COMPOSER,//12
|
||||||
"album_artist"//13
|
"album_artist"//13
|
||||||
), Constants.IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
), Constants.IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,12 @@ import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
import android.provider.MediaStore.Audio.Playlists.*
|
||||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||||
|
import code.name.monkey.retromusic.extensions.getInt
|
||||||
|
import code.name.monkey.retromusic.extensions.getLong
|
||||||
|
import code.name.monkey.retromusic.extensions.getString
|
||||||
|
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong
|
import code.name.monkey.retromusic.model.PlaylistSong
|
||||||
|
@ -42,7 +47,7 @@ object PlaylistSongsLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getPlaylistSongList(context: Context, playlistId: Int): List<Song> {
|
fun getPlaylistSongList(context: Context, playlistId: Long): List<Song> {
|
||||||
val songs = mutableListOf<Song>()
|
val songs = mutableListOf<Song>()
|
||||||
val cursor =
|
val cursor =
|
||||||
makePlaylistSongCursor(
|
makePlaylistSongCursor(
|
||||||
|
@ -64,21 +69,22 @@ object PlaylistSongsLoader {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong {
|
// TODO duplicated in [PlaylistRepository.kt]
|
||||||
val id = cursor.getInt(0)
|
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
|
||||||
val title = cursor.getString(1)
|
val id = cursor.getLong(Members.AUDIO_ID)
|
||||||
val trackNumber = cursor.getInt(2)
|
val title = cursor.getString(AudioColumns.TITLE)
|
||||||
val year = cursor.getInt(3)
|
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||||
val duration = cursor.getLong(4)
|
val year = cursor.getInt(AudioColumns.YEAR)
|
||||||
val data = cursor.getString(5)
|
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||||
val dateModified = cursor.getLong(6)
|
val data = cursor.getString(AudioColumns.DATA)
|
||||||
val albumId = cursor.getInt(7)
|
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||||
val albumName = cursor.getString(8)
|
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||||
val artistId = cursor.getInt(9)
|
val albumName = cursor.getString(AudioColumns.ALBUM)
|
||||||
val artistName = cursor.getString(10)
|
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||||
val idInPlaylist = cursor.getInt(11)
|
val artistName = cursor.getString(AudioColumns.ARTIST)
|
||||||
val composer = cursor.getString(12)
|
val idInPlaylist = cursor.getLong(Members._ID)
|
||||||
val albumArtist = cursor.getString(13)
|
val composer = cursor.getString(AudioColumns.COMPOSER)
|
||||||
|
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||||
return PlaylistSong(
|
return PlaylistSong(
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
|
@ -98,12 +104,12 @@ object PlaylistSongsLoader {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makePlaylistSongCursor(context: Context, playlistId: Int): Cursor? {
|
private fun makePlaylistSongCursor(context: Context, playlistId: Long): Cursor? {
|
||||||
try {
|
try {
|
||||||
return context.contentResolver.query(
|
return context.contentResolver.query(
|
||||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()),
|
Members.getContentUri("external", playlistId),
|
||||||
arrayOf(
|
arrayOf(
|
||||||
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0
|
Members.AUDIO_ID, // 0
|
||||||
AudioColumns.TITLE, // 1
|
AudioColumns.TITLE, // 1
|
||||||
AudioColumns.TRACK, // 2
|
AudioColumns.TRACK, // 2
|
||||||
AudioColumns.YEAR, // 3
|
AudioColumns.YEAR, // 3
|
||||||
|
@ -114,10 +120,10 @@ object PlaylistSongsLoader {
|
||||||
AudioColumns.ALBUM, // 8
|
AudioColumns.ALBUM, // 8
|
||||||
AudioColumns.ARTIST_ID, // 9
|
AudioColumns.ARTIST_ID, // 9
|
||||||
AudioColumns.ARTIST, // 10
|
AudioColumns.ARTIST, // 10
|
||||||
MediaStore.Audio.Playlists.Members._ID,//11
|
Members._ID,//11
|
||||||
AudioColumns.COMPOSER,//12
|
AudioColumns.COMPOSER,//12
|
||||||
"album_artist"//13
|
"album_artist"//13
|
||||||
), IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
), IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
|
||||||
)
|
)
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -41,10 +41,10 @@ interface Repository {
|
||||||
fun historySong(): List<HistoryEntity>
|
fun historySong(): List<HistoryEntity>
|
||||||
fun favorites(): LiveData<List<SongEntity>>
|
fun favorites(): LiveData<List<SongEntity>>
|
||||||
fun observableHistorySongs(): LiveData<List<HistoryEntity>>
|
fun observableHistorySongs(): LiveData<List<HistoryEntity>>
|
||||||
fun albumById(albumId: Int): Album
|
fun albumById(albumId: Long): Album
|
||||||
fun playlistSongs(playlistEntity: PlaylistEntity): LiveData<List<SongEntity>>
|
fun playlistSongs(playlistEntity: PlaylistEntity): LiveData<List<SongEntity>>
|
||||||
suspend fun fetchAlbums(): List<Album>
|
suspend fun fetchAlbums(): List<Album>
|
||||||
suspend fun albumByIdAsync(albumId: Int): Album
|
suspend fun albumByIdAsync(albumId: Long): Album
|
||||||
suspend fun allSongs(): List<Song>
|
suspend fun allSongs(): List<Song>
|
||||||
suspend fun fetchArtists(): List<Artist>
|
suspend fun fetchArtists(): List<Artist>
|
||||||
suspend fun albumArtists(): List<Artist>
|
suspend fun albumArtists(): List<Artist>
|
||||||
|
@ -52,10 +52,10 @@ interface Repository {
|
||||||
suspend fun fetchGenres(): List<Genre>
|
suspend fun fetchGenres(): List<Genre>
|
||||||
suspend fun search(query: String?): MutableList<Any>
|
suspend fun search(query: String?): MutableList<Any>
|
||||||
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
|
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
|
||||||
suspend fun getGenre(genreId: Int): List<Song>
|
suspend fun getGenre(genreId: Long): List<Song>
|
||||||
suspend fun artistInfo(name: String, lang: String?, cache: String?): Result<LastFmArtist>
|
suspend fun artistInfo(name: String, lang: String?, cache: String?): Result<LastFmArtist>
|
||||||
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum>
|
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum>
|
||||||
suspend fun artistById(artistId: Int): Artist
|
suspend fun artistById(artistId: Long): Artist
|
||||||
suspend fun recentArtists(): List<Artist>
|
suspend fun recentArtists(): List<Artist>
|
||||||
suspend fun topArtists(): List<Artist>
|
suspend fun topArtists(): List<Artist>
|
||||||
suspend fun topAlbums(): List<Album>
|
suspend fun topAlbums(): List<Album>
|
||||||
|
@ -70,7 +70,7 @@ interface Repository {
|
||||||
suspend fun playlists(): Home
|
suspend fun playlists(): Home
|
||||||
suspend fun homeSections(): List<Home>
|
suspend fun homeSections(): List<Home>
|
||||||
suspend fun homeSectionsFlow(): Flow<Result<List<Home>>>
|
suspend fun homeSectionsFlow(): Flow<Result<List<Home>>>
|
||||||
suspend fun playlist(playlistId: Int): Playlist
|
suspend fun playlist(playlistId: Long): Playlist
|
||||||
suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs>
|
suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs>
|
||||||
suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
|
suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
|
||||||
suspend fun insertSongs(songs: List<SongEntity>)
|
suspend fun insertSongs(songs: List<SongEntity>)
|
||||||
|
@ -78,7 +78,7 @@ interface Repository {
|
||||||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||||
suspend fun fetchPlaylists(): List<PlaylistEntity>
|
suspend fun fetchPlaylists(): List<PlaylistEntity>
|
||||||
suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>)
|
suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>)
|
||||||
suspend fun renameRoomPlaylist(playlistId: Int, name: String)
|
suspend fun renameRoomPlaylist(playlistId: Long, name: String)
|
||||||
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
||||||
suspend fun removeSongFromPlaylist(songEntity: SongEntity)
|
suspend fun removeSongFromPlaylist(songEntity: SongEntity)
|
||||||
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
||||||
|
@ -93,7 +93,7 @@ interface Repository {
|
||||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||||
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
||||||
suspend fun lyrics(artist: String, title: String): Result<String>
|
suspend fun lyrics(artist: String, title: String): Result<String>
|
||||||
|
@ -126,15 +126,15 @@ class RealRepository(
|
||||||
|
|
||||||
override suspend fun fetchAlbums(): List<Album> = albumRepository.albums()
|
override suspend fun fetchAlbums(): List<Album> = albumRepository.albums()
|
||||||
|
|
||||||
override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId)
|
override suspend fun albumByIdAsync(albumId: Long): Album = albumRepository.album(albumId)
|
||||||
|
|
||||||
override fun albumById(albumId: Int): Album = albumRepository.album(albumId)
|
override fun albumById(albumId: Long): Album = albumRepository.album(albumId)
|
||||||
|
|
||||||
override suspend fun fetchArtists(): List<Artist> = artistRepository.artists()
|
override suspend fun fetchArtists(): List<Artist> = artistRepository.artists()
|
||||||
|
|
||||||
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
|
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
|
||||||
|
|
||||||
override suspend fun artistById(artistId: Int): Artist = artistRepository.artist(artistId)
|
override suspend fun artistById(artistId: Long): Artist = artistRepository.artist(artistId)
|
||||||
|
|
||||||
override suspend fun recentArtists(): List<Artist> = lastAddedRepository.recentArtists()
|
override suspend fun recentArtists(): List<Artist> = lastAddedRepository.recentArtists()
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ class RealRepository(
|
||||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
|
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getGenre(genreId: Int): List<Song> = genreRepository.songs(genreId)
|
override suspend fun getGenre(genreId: Long): List<Song> = genreRepository.songs(genreId)
|
||||||
|
|
||||||
override suspend fun artistInfo(
|
override suspend fun artistInfo(
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -235,7 +235,7 @@ class RealRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun playlist(playlistId: Int) =
|
override suspend fun playlist(playlistId: Long) =
|
||||||
playlistRepository.playlist(playlistId)
|
playlistRepository.playlist(playlistId)
|
||||||
|
|
||||||
override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> =
|
override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> =
|
||||||
|
@ -263,7 +263,7 @@ class RealRepository(
|
||||||
override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) =
|
override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) =
|
||||||
roomRepository.deletePlaylistEntities(playlists)
|
roomRepository.deletePlaylistEntities(playlists)
|
||||||
|
|
||||||
override suspend fun renameRoomPlaylist(playlistId: Int, name: String) =
|
override suspend fun renameRoomPlaylist(playlistId: Long, name: String) =
|
||||||
roomRepository.renamePlaylistEntity(playlistId, name)
|
roomRepository.renamePlaylistEntity(playlistId, name)
|
||||||
|
|
||||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
|
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
|
||||||
|
@ -306,7 +306,7 @@ class RealRepository(
|
||||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||||
roomRepository.deleteSongInPlayCount(playCountEntity)
|
roomRepository.deleteSongInPlayCount(playCountEntity)
|
||||||
|
|
||||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||||
roomRepository.checkSongExistInPlayCount(songId)
|
roomRepository.checkSongExistInPlayCount(songId)
|
||||||
|
|
||||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||||
|
|
|
@ -18,7 +18,7 @@ interface RoomRepository {
|
||||||
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
|
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
|
||||||
suspend fun insertSongs(songs: List<SongEntity>)
|
suspend fun insertSongs(songs: List<SongEntity>)
|
||||||
suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>)
|
suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>)
|
||||||
suspend fun renamePlaylistEntity(playlistId: Int, name: String)
|
suspend fun renamePlaylistEntity(playlistId: Long, name: String)
|
||||||
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
||||||
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
||||||
suspend fun favoritePlaylist(favorite: String): PlaylistEntity
|
suspend fun favoritePlaylist(favorite: String): PlaylistEntity
|
||||||
|
@ -31,7 +31,7 @@ interface RoomRepository {
|
||||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||||
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||||
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||||
|
@ -76,7 +76,7 @@ class RealRoomRepository(
|
||||||
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
|
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
|
||||||
playlistDao.deletePlaylists(playlistEntities)
|
playlistDao.deletePlaylists(playlistEntities)
|
||||||
|
|
||||||
override suspend fun renamePlaylistEntity(playlistId: Int, name: String) =
|
override suspend fun renamePlaylistEntity(playlistId: Long, name: String) =
|
||||||
playlistDao.renamePlaylist(playlistId, name)
|
playlistDao.renamePlaylist(playlistId, name)
|
||||||
|
|
||||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) {
|
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) {
|
||||||
|
@ -95,7 +95,7 @@ class RealRoomRepository(
|
||||||
return if (playlist != null) {
|
return if (playlist != null) {
|
||||||
playlist
|
playlist
|
||||||
} else {
|
} else {
|
||||||
createPlaylist(PlaylistEntity(favorite))
|
createPlaylist(PlaylistEntity(playlistName = favorite))
|
||||||
playlistDao.isPlaylistExists(favorite).first()
|
playlistDao.isPlaylistExists(favorite).first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ class RealRoomRepository(
|
||||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||||
playCountDao.deleteSongInPlayCount(playCountEntity)
|
playCountDao.deleteSongInPlayCount(playCountEntity)
|
||||||
|
|
||||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||||
playCountDao.checkSongExistInPlayCount(songId)
|
playCountDao.checkSongExistInPlayCount(songId)
|
||||||
|
|
||||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||||
|
|
|
@ -18,8 +18,13 @@ import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
import android.provider.MediaStore.Audio.Media
|
||||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||||
import code.name.monkey.retromusic.Constants.baseProjection
|
import code.name.monkey.retromusic.Constants.baseProjection
|
||||||
|
import code.name.monkey.retromusic.extensions.getInt
|
||||||
|
import code.name.monkey.retromusic.extensions.getLong
|
||||||
|
import code.name.monkey.retromusic.extensions.getString
|
||||||
|
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
import code.name.monkey.retromusic.providers.BlacklistStore
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
@ -40,7 +45,7 @@ interface SongRepository {
|
||||||
|
|
||||||
fun song(cursor: Cursor?): Song
|
fun song(cursor: Cursor?): Song
|
||||||
|
|
||||||
fun song(songId: Int): Song
|
fun song(songId: Long): Song
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealSongRepository(private val context: Context) : SongRepository {
|
class RealSongRepository(private val context: Context) : SongRepository {
|
||||||
|
@ -74,14 +79,14 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
||||||
return songs(makeSongCursor(AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%")))
|
return songs(makeSongCursor(AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%")))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun song(songId: Int): Song {
|
override fun song(songId: Long): Song {
|
||||||
return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString())))
|
return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString())))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun songsByFilePath(filePath: String): List<Song> {
|
override fun songsByFilePath(filePath: String): List<Song> {
|
||||||
return songs(
|
return songs(
|
||||||
makeSongCursor(
|
makeSongCursor(
|
||||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
AudioColumns.DATA + "=?",
|
||||||
arrayOf(filePath)
|
arrayOf(filePath)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -90,19 +95,19 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
||||||
private fun getSongFromCursorImpl(
|
private fun getSongFromCursorImpl(
|
||||||
cursor: Cursor
|
cursor: Cursor
|
||||||
): Song {
|
): Song {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(AudioColumns._ID)
|
||||||
val title = cursor.getString(1)
|
val title = cursor.getString(AudioColumns.TITLE)
|
||||||
val trackNumber = cursor.getInt(2)
|
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||||
val year = cursor.getInt(3)
|
val year = cursor.getInt(AudioColumns.YEAR)
|
||||||
val duration = cursor.getLong(4)
|
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||||
val data = cursor.getString(5)
|
val data = cursor.getString(AudioColumns.DATA)
|
||||||
val dateModified = cursor.getLong(6)
|
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||||
val albumId = cursor.getInt(7)
|
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||||
val albumName = cursor.getString(8)
|
val albumName = cursor.getStringOrNull(AudioColumns.ALBUM)
|
||||||
val artistId = cursor.getInt(9)
|
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||||
val artistName = cursor.getString(10)
|
val artistName = cursor.getStringOrNull(AudioColumns.ARTIST)
|
||||||
val composer = cursor.getString(11)
|
val composer = cursor.getStringOrNull(AudioColumns.COMPOSER)
|
||||||
val albumArtist = cursor.getString(12)
|
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||||
return Song(
|
return Song(
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
|
@ -142,18 +147,15 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
||||||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
||||||
}
|
}
|
||||||
selectionFinal =
|
selectionFinal =
|
||||||
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
||||||
try {
|
|
||||||
return context.contentResolver.query(
|
return context.contentResolver.query(
|
||||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
|
||||||
baseProjection,
|
baseProjection,
|
||||||
selectionFinal,
|
selectionFinal,
|
||||||
selectionValuesFinal,
|
selectionValuesFinal,
|
||||||
sortOrder
|
sortOrder
|
||||||
)
|
)
|
||||||
} catch (e: SecurityException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateBlacklistSelection(
|
private fun generateBlacklistSelection(
|
||||||
|
|
|
@ -90,7 +90,7 @@ class MediaSessionCallback(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAndStartPlaying(songs: ArrayList<Song>, itemId: Int) {
|
private fun checkAndStartPlaying(songs: ArrayList<Song>, itemId: Long) {
|
||||||
var songIndex = MusicUtil.indexOfSongInList(songs, itemId)
|
var songIndex = MusicUtil.indexOfSongInList(songs, itemId)
|
||||||
if (songIndex == -1) {
|
if (songIndex == -1) {
|
||||||
songIndex = 0
|
songIndex = 0
|
||||||
|
|
|
@ -618,7 +618,7 @@ public class MusicService extends Service implements
|
||||||
break;
|
break;
|
||||||
case SHUFFLE_MODE_NONE:
|
case SHUFFLE_MODE_NONE:
|
||||||
this.shuffleMode = shuffleMode;
|
this.shuffleMode = shuffleMode;
|
||||||
int currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
|
long currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
|
||||||
playingQueue = new ArrayList<>(originalPlayingQueue);
|
playingQueue = new ArrayList<>(originalPlayingQueue);
|
||||||
int newPosition = 0;
|
int newPosition = 0;
|
||||||
if (getPlayingQueue() != null) {
|
if (getPlayingQueue() != null) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class AutoGeneratedPlaylistBitmap {
|
||||||
if (songPlaylist == null) return null;
|
if (songPlaylist == null) return null;
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
// lấy toàn bộ album id, loại bỏ trùng nhau
|
// lấy toàn bộ album id, loại bỏ trùng nhau
|
||||||
ArrayList<Integer> albumID = new ArrayList<>();
|
List<Long> albumID = new ArrayList<>();
|
||||||
for (Song song : songPlaylist) {
|
for (Song song : songPlaylist) {
|
||||||
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ public class AutoGeneratedPlaylistBitmap {
|
||||||
long start2 = System.currentTimeMillis() - start;
|
long start2 = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
// lấy toàn bộ art tồn tại
|
// lấy toàn bộ art tồn tại
|
||||||
ArrayList<Bitmap> art = new ArrayList<Bitmap>();
|
List<Bitmap> art = new ArrayList<Bitmap>();
|
||||||
for (Integer id : albumID) {
|
for (Long id : albumID) {
|
||||||
Bitmap bitmap = getBitmapWithAlbumId(context, id);
|
Bitmap bitmap = getBitmapWithAlbumId(context, id);
|
||||||
if (bitmap != null) art.add(bitmap);
|
if (bitmap != null) art.add(bitmap);
|
||||||
if (art.size() == 6) break;
|
if (art.size() == 6) break;
|
||||||
|
@ -168,7 +168,7 @@ public class AutoGeneratedPlaylistBitmap {
|
||||||
else return bitmap;
|
else return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Integer id) {
|
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
|
||||||
try {
|
try {
|
||||||
return Glide.with(context)
|
return Glide.with(context)
|
||||||
.load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id))
|
.load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id))
|
||||||
|
|
|
@ -16,6 +16,7 @@ import androidx.core.content.FileProvider
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
|
import code.name.monkey.retromusic.extensions.getLong
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
@ -85,7 +86,7 @@ object MusicUtil : KoinComponent {
|
||||||
return albumArtDir
|
return albumArtDir
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteAlbumArt(context: Context, albumId: Int) {
|
fun deleteAlbumArt(context: Context, albumId: Long) {
|
||||||
val contentResolver = context.contentResolver
|
val contentResolver = context.contentResolver
|
||||||
val localUri = Uri.parse("content://media/external/audio/albumart")
|
val localUri = Uri.parse("content://media/external/audio/albumart")
|
||||||
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null)
|
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null)
|
||||||
|
@ -175,10 +176,9 @@ object MusicUtil : KoinComponent {
|
||||||
return lyrics
|
return lyrics
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMediaStoreAlbumCoverUri(albumId: Int): Uri {
|
fun getMediaStoreAlbumCoverUri(albumId: Long): Uri {
|
||||||
val sArtworkUri =
|
val sArtworkUri = Uri.parse("content://media/external/audio/albumart")
|
||||||
Uri.parse("content://media/external/audio/albumart")
|
return ContentUris.withAppendedId(sArtworkUri, albumId)
|
||||||
return ContentUris.withAppendedId(sArtworkUri, albumId.toLong())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ object MusicUtil : KoinComponent {
|
||||||
return "$songCount $songString"
|
return "$songCount $songString"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSongFileUri(songId: Int): Uri {
|
fun getSongFileUri(songId: Long): Uri {
|
||||||
return ContentUris.withAppendedId(
|
return ContentUris.withAppendedId(
|
||||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||||
songId.toLong()
|
songId.toLong()
|
||||||
|
@ -268,18 +268,13 @@ object MusicUtil : KoinComponent {
|
||||||
return if (year > 0) year.toString() else "-"
|
return if (year > 0) year.toString() else "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun indexOfSongInList(songs: List<Song>, songId: Int): Int {
|
fun indexOfSongInList(songs: List<Song>, songId: Long): Int {
|
||||||
for (i in songs.indices) {
|
return songs.indexOfFirst { it.id == songId }
|
||||||
if (songs[i].id == songId) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun insertAlbumArt(
|
fun insertAlbumArt(
|
||||||
context: Context,
|
context: Context,
|
||||||
albumId: Int,
|
albumId: Long,
|
||||||
path: String?
|
path: String?
|
||||||
) {
|
) {
|
||||||
val contentResolver = context.contentResolver
|
val contentResolver = context.contentResolver
|
||||||
|
@ -306,7 +301,7 @@ object MusicUtil : KoinComponent {
|
||||||
|
|
||||||
fun isFavorite(context: Context, song: Song): Boolean {
|
fun isFavorite(context: Context, song: Song): Boolean {
|
||||||
return PlaylistsUtil
|
return PlaylistsUtil
|
||||||
.doPlaylistContains(context, getFavoritesPlaylist(context).id.toLong(), song.id)
|
.doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFavoritePlaylist(
|
fun isFavoritePlaylist(
|
||||||
|
@ -387,7 +382,7 @@ object MusicUtil : KoinComponent {
|
||||||
// as from the album art cache
|
// as from the album art cache
|
||||||
cursor.moveToFirst()
|
cursor.moveToFirst()
|
||||||
while (!cursor.isAfterLast) {
|
while (!cursor.isAfterLast) {
|
||||||
val id = cursor.getInt(0)
|
val id = cursor.getLong(BaseColumns._ID)
|
||||||
val song: Song = songRepository.song(id)
|
val song: Song = songRepository.song(id)
|
||||||
removeFromQueue(song)
|
removeFromQueue(song)
|
||||||
cursor.moveToNext()
|
cursor.moveToNext()
|
||||||
|
@ -452,7 +447,7 @@ object MusicUtil : KoinComponent {
|
||||||
// as from the album art cache
|
// as from the album art cache
|
||||||
cursor.moveToFirst()
|
cursor.moveToFirst()
|
||||||
while (!cursor.isAfterLast) {
|
while (!cursor.isAfterLast) {
|
||||||
val id: Int = cursor.getInt(0)
|
val id = cursor.getLong(BaseColumns._ID)
|
||||||
val song: Song = RealSongRepository(context).song(id)
|
val song: Song = RealSongRepository(context).song(id)
|
||||||
removeFromQueue(song)
|
removeFromQueue(song)
|
||||||
cursor.moveToNext()
|
cursor.moveToNext()
|
||||||
|
|
|
@ -43,7 +43,7 @@ import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
||||||
|
|
||||||
public class PlaylistsUtil {
|
public class PlaylistsUtil {
|
||||||
|
|
||||||
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
public static long createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
||||||
int id = -1;
|
int id = -1;
|
||||||
if (name != null && name.length() > 0) {
|
if (name != null && name.length() > 0) {
|
||||||
try {
|
try {
|
||||||
|
@ -101,13 +101,13 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addToPlaylist(@NonNull final Context context, final Song song, final int playlistId, final boolean showToastOnFinish) {
|
public static void addToPlaylist(@NonNull final Context context, final Song song, final long playlistId, final boolean showToastOnFinish) {
|
||||||
List<Song> helperList = new ArrayList<>();
|
List<Song> helperList = new ArrayList<>();
|
||||||
helperList.add(song);
|
helperList.add(song);
|
||||||
addToPlaylist(context, helperList, playlistId, showToastOnFinish);
|
addToPlaylist(context, helperList, playlistId, showToastOnFinish);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addToPlaylist(@NonNull final Context context, @NonNull final List<Song> songs, final int playlistId, final boolean showToastOnFinish) {
|
public static void addToPlaylist(@NonNull final Context context, @NonNull final List<Song> songs, final long playlistId, final boolean showToastOnFinish) {
|
||||||
final int size = songs.size();
|
final int size = songs.size();
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
final String[] projection = new String[]{
|
final String[] projection = new String[]{
|
||||||
|
@ -180,7 +180,7 @@ public class PlaylistsUtil {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) {
|
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, long playlistId) {
|
||||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||||
"external", playlistId);
|
"external", playlistId);
|
||||||
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
|
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
|
||||||
|
@ -193,7 +193,7 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
|
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
|
||||||
final int playlistId = songs.get(0).getPlaylistId();
|
final long playlistId = songs.get(0).getPlaylistId();
|
||||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||||
"external", playlistId);
|
"external", playlistId);
|
||||||
String[] selectionArgs = new String[songs.size()];
|
String[] selectionArgs = new String[songs.size()];
|
||||||
|
@ -211,7 +211,7 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) {
|
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final long songId) {
|
||||||
if (playlistId != -1) {
|
if (playlistId != -1) {
|
||||||
try {
|
try {
|
||||||
Cursor c = context.getContentResolver().query(
|
Cursor c = context.getContentResolver().query(
|
||||||
|
@ -229,7 +229,7 @@ public class PlaylistsUtil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) {
|
public static boolean moveItem(@NonNull final Context context, long playlistId, int from, int to) {
|
||||||
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
|
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
|
||||||
playlistId, from, to);
|
playlistId, from, to);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface"
|
android:background="?attr/colorSurface"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:transitionName="@string/transition_album_art"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -46,9 +47,7 @@
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:transitionName="@string/transition_album_art"
|
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/container"
|
app:layout_constraintEnd_toStartOf="@+id/container"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:transitionName="@string/transition_album_art">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
|
@ -48,7 +49,6 @@
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:transitionName="@string/transition_album_art"
|
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
|
android:transitionGroup="true"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_dodgeInsetEdges="bottom"
|
app:layout_dodgeInsetEdges="bottom"
|
||||||
tools:listitem="@layout/item_list" />
|
tools:listitem="@layout/item_list" />
|
||||||
|
|
|
@ -41,9 +41,5 @@
|
||||||
android:label=""
|
android:label=""
|
||||||
tools:layout="@layout/fragment_banner_home" />
|
tools:layout="@layout/fragment_banner_home" />
|
||||||
|
|
||||||
<fragment
|
|
||||||
android:id="@+id/action_import_playlist"
|
|
||||||
android:name="code.name.monkey.retromusic.fragments.playlists.ImportPlaylistFragment"
|
|
||||||
android:label="ImportPlaylist"
|
|
||||||
tools:layout="@layout/fragment_main_activity_recycler_view" />
|
|
||||||
</navigation>
|
</navigation>
|
|
@ -32,7 +32,7 @@
|
||||||
tools:layout="@layout/fragment_album_details">
|
tools:layout="@layout/fragment_album_details">
|
||||||
<argument
|
<argument
|
||||||
android:name="extra_album_id"
|
android:name="extra_album_id"
|
||||||
app:argType="integer" />
|
app:argType="long" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
tools:layout="@layout/fragment_artist_details">
|
tools:layout="@layout/fragment_artist_details">
|
||||||
<argument
|
<argument
|
||||||
android:name="extra_artist_id"
|
android:name="extra_artist_id"
|
||||||
app:argType="integer" />
|
app:argType="long" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<item name="action_album_sort_order_desc" type="id" />
|
<item name="action_album_sort_order_desc" type="id" />
|
||||||
<item name="action_album_sort_order_artist" type="id" />
|
<item name="action_album_sort_order_artist" type="id" />
|
||||||
<item name="action_album_sort_order_year" type="id" />
|
<item name="action_album_sort_order_year" type="id" />
|
||||||
|
<item name="action_import_playlist" type="id" />
|
||||||
<item name="action_artist_sort_order_asc" type="id" />
|
<item name="action_artist_sort_order_asc" type="id" />
|
||||||
<item name="action_artist_sort_order_desc" type="id" />
|
<item name="action_artist_sort_order_desc" type="id" />
|
||||||
<item name="action_song_sort_order_asc" type="id" />
|
<item name="action_song_sort_order_asc" type="id" />
|
||||||
|
|
Loading…
Reference in a new issue