Merge branch 'dev' of https://github.com/tnyeanderson/RetroMusicPlayer into pr/889
This commit is contained in:
commit
022bf3624c
76 changed files with 900 additions and 806 deletions
|
@ -107,6 +107,7 @@ dependencies {
|
|||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||
|
||||
def nav_version = "2.3.0"
|
||||
implementation "androidx.navigation:navigation-runtime-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
},
|
||||
{
|
||||
"name": "Daksh P. Jain",
|
||||
"summary": "Telegram group maintainer",
|
||||
"link": "https://dakshpjain.eu.org",
|
||||
"summary": "Support Representative & Moderator",
|
||||
"link": "https://daksh.eu.org",
|
||||
"profile_image": "https://i.imgur.com/fnYpg65.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Milind Goel",
|
||||
"summary": "Github & Telegram maintainer",
|
||||
"summary": "Support Representative & Moderator",
|
||||
"link": "https://t.me/MilindGoel15",
|
||||
"profile_image": "https://i.imgur.com/Bz4De21_d.jpg"
|
||||
}
|
||||
|
|
|
@ -162,14 +162,14 @@ private val viewModules = module {
|
|||
LibraryViewModel(get())
|
||||
}
|
||||
|
||||
viewModel { (albumId: Int) ->
|
||||
viewModel { (albumId: Long) ->
|
||||
AlbumDetailsViewModel(
|
||||
get(),
|
||||
albumId
|
||||
)
|
||||
}
|
||||
|
||||
viewModel { (artistId: Int) ->
|
||||
viewModel { (artistId: Long) ->
|
||||
ArtistDetailsViewModel(
|
||||
get(),
|
||||
artistId
|
||||
|
|
|
@ -28,8 +28,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
const val APP_UPDATE_REQUEST_CODE = 9002
|
||||
}
|
||||
|
||||
private var blockRequestPermissions = false
|
||||
|
||||
override fun createContentView(): View {
|
||||
return wrapSlidingMusicPanel(R.layout.activity_main_content)
|
||||
}
|
||||
|
@ -64,14 +62,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (!hasPermissions()) {
|
||||
//requestPermissions()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == GENERAL_THEME || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES
|
||||
) {
|
||||
|
@ -107,8 +97,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
MusicPlayerRemote.playFromUri(uri)
|
||||
handled = true
|
||||
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
||||
val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
|
||||
if (id >= 0) {
|
||||
val id = parseLongFromIntent(intent, "playlistId", "playlist")
|
||||
if (id >= 0L) {
|
||||
val position: Int = intent.getIntExtra("position", 0)
|
||||
val songs: List<Song> =
|
||||
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
|
||||
|
@ -116,19 +106,19 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
handled = true
|
||||
}
|
||||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
||||
if (id >= 0) {
|
||||
val id = parseLongFromIntent(intent, "albumId", "album")
|
||||
if (id >= 0L) {
|
||||
val position: Int = intent.getIntExtra("position", 0)
|
||||
MusicPlayerRemote.openQueue(
|
||||
libraryViewModel.albumById(id).songs!!,
|
||||
libraryViewModel.albumById(id).songs,
|
||||
position,
|
||||
true
|
||||
)
|
||||
handled = true
|
||||
}
|
||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||
val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
||||
if (id >= 0) {
|
||||
val id = parseLongFromIntent(intent, "artistId", "artist")
|
||||
if (id >= 0L) {
|
||||
val position: Int = intent.getIntExtra("position", 0)
|
||||
MusicPlayerRemote.openQueue(
|
||||
libraryViewModel.artistById(id).songs,
|
||||
|
@ -145,7 +135,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
|
||||
}
|
||||
|
||||
private fun parseIdFromIntent(
|
||||
private fun parseLongFromIntent(
|
||||
intent: Intent, longKey: String,
|
||||
stringKey: String
|
||||
): Long {
|
||||
|
|
|
@ -40,7 +40,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
val repository by inject<Repository>()
|
||||
|
||||
lateinit var saveFab: MaterialButton
|
||||
protected var id: Int = 0
|
||||
protected var id: Long = 0
|
||||
private set
|
||||
private var paletteColorPrimary: Int = 0
|
||||
private var isInNoImageMode: Boolean = false
|
||||
|
@ -251,7 +251,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
private fun getIntentExtras() {
|
||||
val intentExtras = intent.extras
|
||||
if (intentExtras != null) {
|
||||
id = intentExtras.getInt(EXTRA_ID)
|
||||
id = intentExtras.getLong(EXTRA_ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
|
||||
class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
|
||||
|
||||
companion object {
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import code.name.monkey.retromusic.R
|
|||
import code.name.monkey.retromusic.extensions.appHandleColor
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.ImageUtil
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
||||
|
@ -168,12 +169,8 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
}
|
||||
|
||||
override fun getSongPaths(): List<String> {
|
||||
val songs = repository.albumById(id).songs
|
||||
val paths = ArrayList<String>(songs!!.size)
|
||||
for (song in songs) {
|
||||
paths.add(song.data)
|
||||
}
|
||||
return paths
|
||||
return repository.albumById(id).songs
|
||||
.map(Song::data)
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
|
|
|
@ -71,13 +71,13 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
|
|||
public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
|
||||
CategoryInfo categoryInfo = categoryInfos.get(position);
|
||||
|
||||
holder.checkBox.setChecked(categoryInfo.visible);
|
||||
holder.title.setText(holder.title.getResources().getString(categoryInfo.category.stringRes));
|
||||
holder.checkBox.setChecked(categoryInfo.isVisible());
|
||||
holder.title.setText(holder.title.getResources().getString(categoryInfo.getCategory().getStringRes()));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
|
||||
categoryInfo.visible = !categoryInfo.visible;
|
||||
holder.checkBox.setChecked(categoryInfo.visible);
|
||||
if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
|
||||
categoryInfo.setVisible(!categoryInfo.isVisible());
|
||||
holder.checkBox.setChecked(categoryInfo.isVisible());
|
||||
} else {
|
||||
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
@ -110,9 +110,9 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter<CategoryInfoAdapte
|
|||
}
|
||||
|
||||
private boolean isLastCheckedCategory(CategoryInfo categoryInfo) {
|
||||
if (categoryInfo.visible) {
|
||||
if (categoryInfo.isVisible()) {
|
||||
for (CategoryInfo c : categoryInfos) {
|
||||
if (c != categoryInfo && c.visible) {
|
||||
if (c != categoryInfo && c.isVisible()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ class HomeAdapter(
|
|||
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.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(
|
||||
R.id.artistDetailsFragment,
|
||||
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(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
|
|
|
@ -136,7 +136,7 @@ open class AlbumAdapter(
|
|||
private fun getSongList(albums: List<Album>): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
for (album in albums) {
|
||||
songs.addAll(album.songs!!)
|
||||
songs.addAll(album.songs)
|
||||
}
|
||||
return songs
|
||||
}
|
||||
|
@ -170,8 +170,7 @@ open class AlbumAdapter(
|
|||
if (isInQuickSelectMode) {
|
||||
toggleChecked(layoutPosition)
|
||||
} else {
|
||||
println(dataSet[layoutPosition].id)
|
||||
image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) }
|
||||
albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.dialogs.LyricsDialog
|
||||
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
|
@ -91,7 +90,7 @@ class AlbumCoverPagerAdapter(
|
|||
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
||||
albumCover = view.findViewById(R.id.player_image)
|
||||
albumCover.setOnClickListener {
|
||||
LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
||||
//LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
||||
showLyricsDialog()
|
||||
}
|
||||
return view
|
||||
|
|
|
@ -113,6 +113,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
|
|||
itemView.setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getSwipeableContainerView() {
|
||||
return null;
|
||||
|
@ -129,11 +130,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
|
|||
}
|
||||
|
||||
public void setImageTransitionName(@NonNull String transitionName) {
|
||||
if (imageContainerCard != null) {
|
||||
itemView.setTransitionName(transitionName);
|
||||
/* if (imageContainerCard != null) {
|
||||
imageContainerCard.setTransitionName(transitionName);
|
||||
}
|
||||
if (image != null) {
|
||||
image.setTransitionName(transitionName);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.FragmentActivity
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.R.menu
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.toSongEntity
|
||||
import code.name.monkey.retromusic.db.toSongs
|
||||
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||
|
|
|
@ -13,7 +13,7 @@ interface HistoryDao {
|
|||
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
||||
|
||||
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
||||
suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
|
||||
suspend fun isSongPresentInHistory(songId: Long): HistoryEntity?
|
||||
|
||||
@Update
|
||||
suspend fun updateHistorySong(historyEntity: HistoryEntity)
|
||||
|
|
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
|||
@Entity
|
||||
class HistoryEntity(
|
||||
@PrimaryKey
|
||||
val id: Int,
|
||||
val id: Long,
|
||||
val title: String,
|
||||
@ColumnInfo(name = "track_number")
|
||||
val trackNumber: Int,
|
||||
|
@ -17,11 +17,11 @@ class HistoryEntity(
|
|||
@ColumnInfo(name = "date_modified")
|
||||
val dateModified: Long,
|
||||
@ColumnInfo(name = "album_id")
|
||||
val albumId: Int,
|
||||
val albumId: Long,
|
||||
@ColumnInfo(name = "album_name")
|
||||
val albumName: String,
|
||||
@ColumnInfo(name = "artist_id")
|
||||
val artistId: Int,
|
||||
val artistId: Long,
|
||||
@ColumnInfo(name = "artist_name")
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
|
|
|
@ -14,14 +14,14 @@ interface PlayCountDao {
|
|||
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
|
||||
@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")
|
||||
fun playCountSongs(): List<PlayCountEntity>
|
||||
|
||||
@Query("DELETE FROM SongEntity WHERE id =:songId")
|
||||
fun deleteSong(songId: Int)
|
||||
fun deleteSong(songId: Long)
|
||||
|
||||
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
|
||||
fun updateQuantity(id: Int)
|
||||
fun updateQuantity(id: Long)
|
||||
}
|
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
|||
@Entity
|
||||
class PlayCountEntity(
|
||||
@PrimaryKey
|
||||
val id: Int,
|
||||
val id: Long,
|
||||
val title: String,
|
||||
@ColumnInfo(name = "track_number")
|
||||
val trackNumber: Int,
|
||||
|
@ -17,11 +17,11 @@ class PlayCountEntity(
|
|||
@ColumnInfo(name = "date_modified")
|
||||
val dateModified: Long,
|
||||
@ColumnInfo(name = "album_id")
|
||||
val albumId: Int,
|
||||
val albumId: Long,
|
||||
@ColumnInfo(name = "album_name")
|
||||
val albumName: String,
|
||||
@ColumnInfo(name = "artist_id")
|
||||
val artistId: Int,
|
||||
val artistId: Long,
|
||||
@ColumnInfo(name = "artist_name")
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
|
|
|
@ -9,7 +9,7 @@ interface PlaylistDao {
|
|||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||
|
||||
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
|
||||
suspend fun renamePlaylist(playlistId: Int, name: String)
|
||||
suspend fun renamePlaylist(playlistId: Long, name: String)
|
||||
|
||||
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
|
||||
fun isPlaylistExists(name: String): List<PlaylistEntity>
|
||||
|
@ -18,10 +18,10 @@ interface PlaylistDao {
|
|||
suspend fun playlists(): List<PlaylistEntity>
|
||||
|
||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||
suspend fun deletePlaylistSongs(playlistId: Int)
|
||||
suspend fun deletePlaylistSongs(playlistId: Long)
|
||||
|
||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||
suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int)
|
||||
suspend fun deleteSongFromPlaylist(playlistId: Long, songId: Long)
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM PlaylistEntity")
|
||||
|
@ -31,10 +31,10 @@ interface PlaylistDao {
|
|||
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
|
||||
|
||||
@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")
|
||||
fun songsFromPlaylist(playlistId: Int): LiveData<List<SongEntity>>
|
||||
fun songsFromPlaylist(playlistId: Long): LiveData<List<SongEntity>>
|
||||
|
||||
@Delete
|
||||
suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
|
||||
|
@ -47,10 +47,10 @@ interface PlaylistDao {
|
|||
|
||||
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||
fun favoritesSongsLiveData(playlistId: Int): LiveData<List<SongEntity>>
|
||||
fun favoritesSongsLiveData(playlistId: Long): LiveData<List<SongEntity>>
|
||||
|
||||
@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
|
||||
@Parcelize
|
||||
class PlaylistEntity(
|
||||
@ColumnInfo(name = "playlist_name")
|
||||
val playlistName: String
|
||||
) : Parcelable {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@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
|
||||
@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)])
|
||||
class SongEntity(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "song_key")
|
||||
val songPrimaryKey: Long = 0L,
|
||||
@ColumnInfo(name = "playlist_creator_id")
|
||||
val playlistCreatorId: Int,
|
||||
val id: Int,
|
||||
val playlistCreatorId: Long,
|
||||
val id: Long,
|
||||
val title: String,
|
||||
@ColumnInfo(name = "track_number")
|
||||
val trackNumber: Int,
|
||||
|
@ -22,19 +25,15 @@ class SongEntity(
|
|||
@ColumnInfo(name = "date_modified")
|
||||
val dateModified: Long,
|
||||
@ColumnInfo(name = "album_id")
|
||||
val albumId: Int,
|
||||
val albumId: Long,
|
||||
@ColumnInfo(name = "album_name")
|
||||
val albumName: String,
|
||||
@ColumnInfo(name = "artist_id")
|
||||
val artistId: Int,
|
||||
val artistId: Long,
|
||||
@ColumnInfo(name = "artist_name")
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
@ColumnInfo(name = "album_artist")
|
||||
val albumArtist: String?
|
||||
) : Parcelable {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "song_key")
|
||||
var songPrimaryKey: Long = 0
|
||||
}
|
||||
) : Parcelable
|
||||
|
||||
|
|
|
@ -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 {
|
||||
it.toSongEntity(playlistId)
|
||||
}
|
||||
}
|
||||
|
||||
fun Song.toHistoryEntity(timePlayed: Long): HistoryEntity {
|
||||
return HistoryEntity(
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist,
|
||||
timePlayed = timePlayed
|
||||
)
|
||||
}
|
||||
|
||||
fun Song.toSongEntity(playListId: Long): SongEntity {
|
||||
return SongEntity(
|
||||
playlistCreatorId = playListId,
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun SongEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun PlayCountEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun HistoryEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun Song.toPlayCount(): PlayCountEntity {
|
||||
return PlayCountEntity(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist,
|
||||
System.currentTimeMillis(),
|
||||
1
|
||||
id = id,
|
||||
title = title,
|
||||
trackNumber = trackNumber,
|
||||
year = year,
|
||||
duration = duration,
|
||||
data = data,
|
||||
dateModified = dateModified,
|
||||
albumId = albumId,
|
||||
albumName = albumName,
|
||||
artistId = artistId,
|
||||
artistName = artistName,
|
||||
composer = composer,
|
||||
albumArtist = albumArtist,
|
||||
timePlayed = System.currentTimeMillis(),
|
||||
playCount = 1
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import code.name.monkey.retromusic.EXTRA_SONG
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.toSongEntity
|
||||
import code.name.monkey.retromusic.extensions.colorButtons
|
||||
import code.name.monkey.retromusic.extensions.extra
|
||||
import code.name.monkey.retromusic.extensions.materialDialog
|
||||
|
@ -56,8 +57,8 @@ class CreatePlaylistDialog : DialogFragment() {
|
|||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
|
||||
val playlistId: Long =
|
||||
libraryViewModel.createPlaylist(PlaylistEntity(playlistName))
|
||||
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) })
|
||||
libraryViewModel.createPlaylist(PlaylistEntity(playlistName = playlistName))
|
||||
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) })
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
||||
|
|
|
@ -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,8 +3,11 @@ package code.name.monkey.retromusic.fragments
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -178,11 +181,21 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
|
||||
|
||||
|
||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
||||
|
||||
override fun onArtist(artistId: Long, imageView: ImageView) {
|
||||
findNavController().navigate(
|
||||
R.id.artistDetailsFragment,
|
||||
bundleOf(EXTRA_ARTIST_ID to artistId),
|
||||
null,
|
||||
FragmentNavigatorExtras(imageView to getString(R.string.transition_artist_image))
|
||||
)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
|
||||
override fun onAlbumClick(albumId: Long, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(view to getString(R.string.transition_album_art))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import code.name.monkey.retromusic.db.toSongEntity
|
||||
import code.name.monkey.retromusic.fragments.ReloadType.*
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
|
@ -75,7 +76,6 @@ class LibraryViewModel(
|
|||
}
|
||||
|
||||
fun getHome(): LiveData<List<Home>> {
|
||||
fetchHomeSections()
|
||||
return home
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ class LibraryViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun renameRoomPlaylist(playListId: Int, name: String) = viewModelScope.launch(IO) {
|
||||
fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
|
||||
repository.renameRoomPlaylist(playListId, name)
|
||||
}
|
||||
|
||||
|
@ -200,8 +200,8 @@ class LibraryViewModel(
|
|||
repository.deleteRoomPlaylist(playlists)
|
||||
}
|
||||
|
||||
suspend fun albumById(id: Int) = repository.albumById(id)
|
||||
suspend fun artistById(id: Int) = repository.artistById(id)
|
||||
suspend fun albumById(id: Long) = repository.albumById(id)
|
||||
suspend fun artistById(id: Long) = repository.artistById(id)
|
||||
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
||||
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
||||
suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs)
|
||||
|
@ -224,9 +224,9 @@ class LibraryViewModel(
|
|||
}
|
||||
repository.insertSongs(songEntities)
|
||||
} else {
|
||||
val playListId = createPlaylist(PlaylistEntity(playlist.name))
|
||||
val playListId = createPlaylist(PlaylistEntity(playlistName = playlist.name))
|
||||
val songEntities = playlist.getSongs().map {
|
||||
it.toSongEntity(playListId.toInt())
|
||||
it.toSongEntity(playListId)
|
||||
}
|
||||
repository.insertSongs(songEntities)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.core.text.HtmlCompat
|
|||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
|
@ -46,6 +47,8 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
|||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.transition.platform.MaterialArcMotion
|
||||
import com.google.android.material.transition.platform.MaterialContainerTransform
|
||||
import kotlinx.android.synthetic.main.fragment_album_content.*
|
||||
import kotlinx.android.synthetic.main.fragment_album_details.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -70,8 +73,16 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
private val savedSortOrder: String
|
||||
get() = PreferenceUtil.albumDetailSongSortOrder
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
sharedElementEnterTransition = MaterialContainerTransform().apply {
|
||||
duration = 1000L
|
||||
pathMotion = MaterialArcMotion()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
|
@ -79,7 +90,6 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
toolbar.title = " "
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
||||
println(Thread.currentThread().name)
|
||||
startPostponedEnterTransition()
|
||||
showAlbum(it)
|
||||
})
|
||||
|
@ -92,11 +102,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
bundleOf(EXTRA_ARTIST_ID to album.artistId)
|
||||
)
|
||||
}
|
||||
playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
|
||||
playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs, 0, true) }
|
||||
|
||||
shuffleAction.setOnClickListener {
|
||||
MusicPlayerRemote.openAndShuffleQueue(
|
||||
album.songs!!,
|
||||
album.songs,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
@ -135,7 +145,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
}
|
||||
|
||||
private fun showAlbum(album: Album) {
|
||||
if (album.songs!!.isEmpty()) {
|
||||
if (album.songs.isEmpty()) {
|
||||
return
|
||||
}
|
||||
this.album = album
|
||||
|
@ -255,10 +265,12 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
playAction.applyOutlineColor(color)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
override fun onAlbumClick(albumId: Long, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId)
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(view to getString(R.string.transition_album_art))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -350,29 +362,31 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
|
||||
private fun setSaveSortOrder(sortOrder: String) {
|
||||
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
||||
when (sortOrder) {
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
val songs = when (sortOrder) {
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.trackNumber.compareTo(
|
||||
o2.trackNumber
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.title.compareTo(
|
||||
o2.title
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||
o2.title.compareTo(
|
||||
o1.title
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.duration.compareTo(
|
||||
o2.duration
|
||||
)
|
||||
})
|
||||
}
|
||||
album.songs?.let { simpleSongAdapter.swapDataSet(it) }
|
||||
else -> throw IllegalArgumentException("invalid $sortOrder")
|
||||
}
|
||||
album = album.copy(songs = songs)
|
||||
simpleSongAdapter.swapDataSet(album.songs)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -13,15 +13,14 @@ import kotlinx.coroutines.Dispatchers.IO
|
|||
|
||||
class AlbumDetailsViewModel(
|
||||
private val repository: RealRepository,
|
||||
private val albumId: Int
|
||||
private val albumId: Long
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
||||
val album = repository.albumByIdAsync(albumId)
|
||||
emit(album)
|
||||
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)
|
||||
emit(artist)
|
||||
}
|
||||
|
@ -32,7 +31,7 @@ class AlbumDetailsViewModel(
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,17 @@ import code.name.monkey.retromusic.helper.SortOrder
|
|||
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
|
||||
|
||||
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||
AlbumClickListener {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer {
|
||||
|
@ -43,7 +49,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
|||
return AlbumAdapter(
|
||||
requireActivity(),
|
||||
dataSet,
|
||||
R.layout.item_grid,
|
||||
itemLayoutRes(),
|
||||
null,
|
||||
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(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
|
@ -285,5 +291,5 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
|||
}
|
||||
|
||||
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.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
||||
|
@ -38,7 +37,6 @@ import code.name.monkey.retromusic.network.model.LastFmArtist
|
|||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||
|
@ -199,14 +197,12 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
}
|
||||
|
||||
private fun setColors(color: Int) {
|
||||
val finalColor = if (PreferenceUtil.isAdaptiveColor) color
|
||||
else ThemeStore.accentColor(requireContext())
|
||||
shuffleAction.applyColor(finalColor)
|
||||
playAction.applyOutlineColor(finalColor)
|
||||
shuffleAction.applyColor(color)
|
||||
playAction.applyOutlineColor(color)
|
||||
}
|
||||
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
override fun onAlbumClick(albumId: Long, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
|
|
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.Dispatchers.IO
|
|||
|
||||
class ArtistDetailsViewModel(
|
||||
private val realRepository: RealRepository,
|
||||
private val artistId: Int
|
||||
private val artistId: Long
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
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.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
|
||||
|
||||
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||
ArtistClickListener {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -46,7 +51,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
|||
return ArtistAdapter(
|
||||
requireActivity(),
|
||||
dataSet,
|
||||
R.layout.item_grid_circle,
|
||||
itemLayoutRes(),
|
||||
null,
|
||||
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)
|
||||
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
||||
}
|
||||
|
@ -258,5 +263,5 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
|||
}
|
||||
|
||||
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.db.PlaylistEntity
|
||||
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.extensions.hide
|
||||
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.adapter.GenreAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
|
||||
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
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.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
import kotlinx.android.synthetic.main.abs_playlists.*
|
||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||
import kotlinx.android.synthetic.main.home_content.*
|
||||
|
@ -43,6 +44,10 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
|||
|
||||
class HomeFragment :
|
||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||
|
||||
|
|
|
@ -14,12 +14,16 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import code.name.monkey.retromusic.db.toSongEntity
|
||||
import code.name.monkey.retromusic.extensions.hide
|
||||
import code.name.monkey.retromusic.extensions.ripAlpha
|
||||
import code.name.monkey.retromusic.extensions.show
|
||||
|
@ -36,7 +40,7 @@ import code.name.monkey.retromusic.util.MusicUtil
|
|||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
||||
|
@ -45,6 +49,9 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
|
|||
import kotlinx.android.synthetic.main.fragment_gradient_controls.*
|
||||
import kotlinx.android.synthetic.main.fragment_gradient_player.*
|
||||
import kotlinx.android.synthetic.main.status_bar.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player),
|
||||
MusicProgressViewUpdateHelper.Callback,
|
||||
|
@ -61,7 +68,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
||||
private lateinit var linearLayoutManager: LinearLayoutManager
|
||||
|
||||
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
private val bottomSheetCallbackList = object : BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
playerQueueSheet.setPadding(
|
||||
|
@ -74,11 +81,11 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
when (newState) {
|
||||
BottomSheetBehavior.STATE_EXPANDED,
|
||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
||||
STATE_EXPANDED,
|
||||
STATE_DRAGGING -> {
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
}
|
||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||
STATE_COLLAPSED -> {
|
||||
resetToCurrentPosition()
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
}
|
||||
|
@ -167,9 +174,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
|
||||
override fun onBackPressed(): Boolean {
|
||||
var wasExpanded = false
|
||||
if (getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
wasExpanded = getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED
|
||||
getQueuePanel().state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
if (getQueuePanel().state == STATE_EXPANDED) {
|
||||
wasExpanded = getQueuePanel().state == STATE_EXPANDED
|
||||
getQueuePanel().state = STATE_COLLAPSED
|
||||
return wasExpanded
|
||||
}
|
||||
return wasExpanded
|
||||
|
@ -216,7 +223,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
override fun toggleFavorite(song: Song) {
|
||||
super.toggleFavorite(song)
|
||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||
updateIsFavorite()
|
||||
updateIsFavoriteIcon()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +231,23 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
toggleFavorite(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
|
||||
private fun updateIsFavoriteIcon() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val song: SongEntity =
|
||||
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
|
||||
withContext(Dispatchers.Main) {
|
||||
val icon =
|
||||
if (isFavorite) R.drawable.ic_favorite
|
||||
else R.drawable.ic_favorite_border
|
||||
songFavourite.setImageResource(icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideVolumeIfAvailable() {
|
||||
if (PreferenceUtil.isVolumeVisibilityMode) {
|
||||
childFragmentManager.beginTransaction()
|
||||
|
@ -241,6 +265,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
updatePlayPauseDrawableState()
|
||||
updatePlayPauseDrawableState()
|
||||
updateQueue()
|
||||
updateIsFavoriteIcon()
|
||||
}
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
|
@ -259,6 +284,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
super.onPlayingMetaChanged()
|
||||
updateSong()
|
||||
updateQueuePosition()
|
||||
updateIsFavoriteIcon()
|
||||
}
|
||||
|
||||
override fun onQueueChanged() {
|
||||
|
@ -359,13 +385,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
private fun updateLabel() {
|
||||
(MusicPlayerRemote.playingQueue.size - 1).apply {
|
||||
if (this == (MusicPlayerRemote.position)) {
|
||||
nextSong.hide()
|
||||
nextSong.text = "Last song"
|
||||
} else {
|
||||
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
||||
nextSong.apply {
|
||||
text = title
|
||||
show()
|
||||
}
|
||||
nextSong.text = title
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,12 +483,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
progressSlider.max = total
|
||||
|
||||
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
|
||||
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.start()
|
||||
|
||||
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
||||
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
||||
}
|
||||
|
|
|
@ -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.adapter.playlist.PlaylistAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
|
||||
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
|
|
@ -15,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel()
|
|||
|
||||
fun search(query: String?) = viewModelScope.launch(IO) {
|
||||
val result = realRepository.search(query)
|
||||
results.value = result
|
||||
results.postValue(result)
|
||||
}
|
||||
}
|
|
@ -12,10 +12,14 @@ import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeF
|
|||
import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.transition.platform.MaterialFadeThrough
|
||||
|
||||
|
||||
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
|
|
@ -7,8 +7,8 @@ import org.koin.core.KoinComponent
|
|||
import org.koin.core.inject
|
||||
|
||||
abstract class AbsCustomPlaylist(
|
||||
id: Int = -1,
|
||||
name: String = ""
|
||||
id: Long,
|
||||
name: String
|
||||
) : Playlist(id, name), KoinComponent {
|
||||
|
||||
abstract fun songs(): List<Song>
|
||||
|
|
|
@ -14,19 +14,15 @@
|
|||
|
||||
package code.name.monkey.retromusic.model
|
||||
|
||||
import java.util.*
|
||||
|
||||
class Album {
|
||||
|
||||
val songs: ArrayList<Song>?
|
||||
|
||||
val id: Int
|
||||
get() = safeGetFirstSong().albumId
|
||||
data class Album(
|
||||
val id: Long,
|
||||
val songs: List<Song>
|
||||
) {
|
||||
|
||||
val title: String?
|
||||
get() = safeGetFirstSong().albumName
|
||||
|
||||
val artistId: Int
|
||||
val artistId: Long
|
||||
get() = safeGetFirstSong().artistId
|
||||
|
||||
val artistName: String?
|
||||
|
@ -39,20 +35,17 @@ class Album {
|
|||
get() = safeGetFirstSong().dateModified
|
||||
|
||||
val songCount: Int
|
||||
get() = songs!!.size
|
||||
get() = songs.size
|
||||
|
||||
val albumArtist: String?
|
||||
get() = safeGetFirstSong().albumArtist
|
||||
|
||||
constructor(songs: ArrayList<Song>) {
|
||||
this.songs = songs
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.songs = ArrayList()
|
||||
}
|
||||
|
||||
fun safeGetFirstSong(): Song {
|
||||
return if (songs!!.isEmpty()) Song.emptySong else songs[0]
|
||||
return songs.firstOrNull() ?: Song.emptySong
|
||||
}
|
||||
|
||||
companion object {
|
||||
val empty = Album(-1, emptyList())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,17 +15,20 @@
|
|||
package code.name.monkey.retromusic.model
|
||||
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.util.*
|
||||
|
||||
class Artist {
|
||||
val albums: ArrayList<Album>?
|
||||
|
||||
val id: Int
|
||||
get() = safeGetFirstAlbum().artistId
|
||||
data class Artist(
|
||||
val id: Long,
|
||||
val albums: List<Album>
|
||||
) {
|
||||
|
||||
val name: String
|
||||
get() {
|
||||
val name = safeGetFirstAlbum().safeGetFirstSong().albumArtist
|
||||
if (PreferenceUtil.albumArtistsOnly && MusicUtil.isVariousArtists(name)) {
|
||||
return VARIOUS_ARTISTS_DISPLAY_NAME
|
||||
}
|
||||
return if (MusicUtil.isArtistNameUnknown(name)) {
|
||||
UNKNOWN_ARTIST_DISPLAY_NAME
|
||||
} else safeGetFirstAlbum().safeGetFirstSong().artistName
|
||||
|
@ -34,37 +37,27 @@ class Artist {
|
|||
val songCount: Int
|
||||
get() {
|
||||
var songCount = 0
|
||||
for (album in albums!!) {
|
||||
for (album in albums) {
|
||||
songCount += album.songCount
|
||||
}
|
||||
return songCount
|
||||
}
|
||||
|
||||
val albumCount: Int
|
||||
get() = albums!!.size
|
||||
get() = albums.size
|
||||
|
||||
val songs: ArrayList<Song>
|
||||
get() {
|
||||
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()
|
||||
}
|
||||
val songs: List<Song>
|
||||
get() = albums.flatMap { it.songs }
|
||||
|
||||
fun safeGetFirstAlbum(): Album {
|
||||
return if (albums!!.isEmpty()) Album() else albums[0]
|
||||
return albums.firstOrNull() ?: Album.empty
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
|
||||
const val VARIOUS_ARTISTS_DISPLAY_NAME = "Various Artists"
|
||||
const val VARIOUS_ARTISTS_ID : Long = -2
|
||||
val empty = Artist(-1, emptyList())
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
class Contributor(
|
||||
data class Contributor(
|
||||
val name: String,
|
||||
val summary: String,
|
||||
val link: String, @SerializedName("profile_image") val profileImage: String
|
||||
val link: String,
|
||||
@SerializedName("profile_image")
|
||||
val profileImage: String
|
||||
)
|
|
@ -18,4 +18,8 @@ import android.os.Parcelable
|
|||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class Genre(val id: Int = -1, val name: String, val songCount: Int) : Parcelable
|
||||
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 code.name.monkey.retromusic.HomeSection
|
||||
|
||||
class Home(
|
||||
data class Home(
|
||||
val arrayList: List<Any>,
|
||||
@HomeSection
|
||||
val homeSection: Int,
|
||||
|
|
|
@ -10,10 +10,14 @@ import org.koin.core.get
|
|||
|
||||
@Parcelize
|
||||
open class Playlist(
|
||||
val id: Int = -1,
|
||||
val name: String = ""
|
||||
val id: Long,
|
||||
val name: String
|
||||
) : Parcelable, KoinComponent {
|
||||
|
||||
companion object {
|
||||
val empty = Playlist(-1, "")
|
||||
}
|
||||
|
||||
// this default implementation covers static playlists
|
||||
fun getSongs(): List<Song> {
|
||||
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 kotlinx.android.parcel.Parcelize
|
||||
|
||||
// update equals and hashcode if fields changes
|
||||
@Parcelize
|
||||
open class Song(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val trackNumber: Int,
|
||||
val year: Int,
|
||||
val duration: Long,
|
||||
val data: String,
|
||||
val dateModified: Long,
|
||||
val albumId: Int,
|
||||
val albumName: String,
|
||||
val artistId: Int,
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
val albumArtist: String?
|
||||
open val id: Long,
|
||||
open val title: String,
|
||||
open val trackNumber: Int,
|
||||
open val year: Int,
|
||||
open val duration: Long,
|
||||
open val data: String,
|
||||
open val dateModified: Long,
|
||||
open val albumId: Long,
|
||||
open val albumName: String,
|
||||
open val artistId: Long,
|
||||
open val artistName: String,
|
||||
open val composer: String?,
|
||||
open val albumArtist: String?
|
||||
) : Parcelable {
|
||||
fun toHistoryEntity(timePlayed: Long): HistoryEntity {
|
||||
return HistoryEntity(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist,
|
||||
timePlayed
|
||||
)
|
||||
|
||||
|
||||
// need to override manually because is open and cannot be a data class
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Song
|
||||
|
||||
if (id != other.id) return false
|
||||
if (title != other.title) return false
|
||||
if (trackNumber != other.trackNumber) return false
|
||||
if (year != other.year) return false
|
||||
if (duration != other.duration) return false
|
||||
if (data != other.data) return false
|
||||
if (dateModified != other.dateModified) return false
|
||||
if (albumId != other.albumId) return false
|
||||
if (albumName != other.albumName) return false
|
||||
if (artistId != other.artistId) return false
|
||||
if (artistName != other.artistName) return false
|
||||
if (composer != other.composer) return false
|
||||
if (albumArtist != other.albumArtist) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun toSongEntity(playListId: Int): SongEntity {
|
||||
return SongEntity(
|
||||
playListId,
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
)
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + title.hashCode()
|
||||
result = 31 * result + trackNumber
|
||||
result = 31 * result + year
|
||||
result = 31 * result + duration.hashCode()
|
||||
result = 31 * result + data.hashCode()
|
||||
result = 31 * result + dateModified.hashCode()
|
||||
result = 31 * result + albumId.hashCode()
|
||||
result = 31 * result + albumName.hashCode()
|
||||
result = 31 * result + artistId.hashCode()
|
||||
result = 31 * result + artistName.hashCode()
|
||||
result = 31 * result + (composer?.hashCode() ?: 0)
|
||||
result = 31 * result + (albumArtist?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,19 +83,19 @@ open class Song(
|
|||
|
||||
@JvmStatic
|
||||
val emptySong = Song(
|
||||
-1,
|
||||
"",
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
"",
|
||||
-1,
|
||||
-1,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
"",
|
||||
""
|
||||
id = -1,
|
||||
title = "",
|
||||
trackNumber = -1,
|
||||
year = -1,
|
||||
duration = -1,
|
||||
data = "",
|
||||
dateModified = -1,
|
||||
albumId = -1,
|
||||
albumName = "",
|
||||
artistId = -1,
|
||||
artistName = "",
|
||||
composer = "",
|
||||
albumArtist = ""
|
||||
)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,9 @@ import code.name.monkey.retromusic.R
|
|||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||
|
||||
abstract class AbsSmartPlaylist(
|
||||
name: String = "",
|
||||
name: String,
|
||||
@DrawableRes val iconRes: Int = R.drawable.ic_queue_music
|
||||
) : AbsCustomPlaylist(-Math.abs(31 * name.hashCode() + iconRes * name.hashCode() * 31 * 31), name)
|
||||
) : AbsCustomPlaylist(
|
||||
id = PlaylistIdGenerator(name, iconRes),
|
||||
name = name
|
||||
)
|
|
@ -7,12 +7,11 @@ import kotlinx.android.parcel.Parcelize
|
|||
import org.koin.core.KoinComponent
|
||||
|
||||
@Parcelize
|
||||
class HistoryPlaylist :
|
||||
AbsSmartPlaylist(
|
||||
App.getContext().getString(R.string.history),
|
||||
R.drawable.ic_history
|
||||
),
|
||||
KoinComponent {
|
||||
class HistoryPlaylist : AbsSmartPlaylist(
|
||||
name = App.getContext().getString(R.string.history),
|
||||
iconRes = R.drawable.ic_history
|
||||
), KoinComponent {
|
||||
|
||||
override fun songs(): List<Song> {
|
||||
return topPlayedRepository.recentlyPlayedTracks()
|
||||
}
|
||||
|
|
|
@ -6,8 +6,10 @@ import code.name.monkey.retromusic.model.Song
|
|||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class LastAddedPlaylist :
|
||||
AbsSmartPlaylist(App.getContext().getString(R.string.last_added), R.drawable.ic_library_add) {
|
||||
class LastAddedPlaylist : AbsSmartPlaylist(
|
||||
name = App.getContext().getString(R.string.last_added),
|
||||
iconRes = R.drawable.ic_library_add
|
||||
) {
|
||||
override fun songs(): List<Song> {
|
||||
return lastAddedRepository.recentSongs()
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
|
|||
|
||||
@Parcelize
|
||||
class NotPlayedPlaylist : AbsSmartPlaylist(
|
||||
App.getContext().getString(R.string.not_recently_played),
|
||||
R.drawable.ic_watch_later
|
||||
name = App.getContext().getString(R.string.not_recently_played),
|
||||
iconRes = R.drawable.ic_watch_later
|
||||
) {
|
||||
override fun songs(): List<Song> {
|
||||
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
|
||||
class ShuffleAllPlaylist : AbsSmartPlaylist(
|
||||
App.getContext().getString(R.string.action_shuffle_all),
|
||||
R.drawable.ic_shuffle
|
||||
name = App.getContext().getString(R.string.action_shuffle_all),
|
||||
iconRes = R.drawable.ic_shuffle
|
||||
) {
|
||||
override fun songs(): List<Song> {
|
||||
return songRepository.songs()
|
||||
|
|
|
@ -7,8 +7,8 @@ import kotlinx.android.parcel.Parcelize
|
|||
|
||||
@Parcelize
|
||||
class TopTracksPlaylist : AbsSmartPlaylist(
|
||||
App.getContext().getString(R.string.my_top_tracks),
|
||||
R.drawable.ic_trending_up
|
||||
name = App.getContext().getString(R.string.my_top_tracks),
|
||||
iconRes = R.drawable.ic_trending_up
|
||||
) {
|
||||
override fun songs(): List<Song> {
|
||||
return topPlayedRepository.topTracks()
|
||||
|
|
|
@ -31,7 +31,7 @@ interface AlbumRepository {
|
|||
|
||||
fun albums(query: String): List<Album>
|
||||
|
||||
fun album(albumId: Int): Album
|
||||
fun album(albumId: Long): Album
|
||||
}
|
||||
|
||||
class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
||||
|
@ -59,70 +59,42 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
|||
return splitIntoAlbums(songs)
|
||||
}
|
||||
|
||||
override fun album(albumId: Int): Album {
|
||||
override fun album(albumId: Long): Album {
|
||||
val cursor = songRepository.makeSongCursor(
|
||||
AudioColumns.ALBUM_ID + "=?",
|
||||
arrayOf(albumId.toString()),
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
val songs = songRepository.songs(cursor)
|
||||
val album = Album(ArrayList(songs))
|
||||
val album = Album(albumId, songs)
|
||||
sortAlbumSongs(album)
|
||||
return album
|
||||
}
|
||||
|
||||
fun splitIntoAlbums(
|
||||
songs: List<Song>?
|
||||
songs: List<Song>
|
||||
): List<Album> {
|
||||
val albums = ArrayList<Album>()
|
||||
if (songs != null) {
|
||||
for (song in songs) {
|
||||
getOrCreateAlbum(albums, song.albumId).songs?.add(song)
|
||||
}
|
||||
}
|
||||
for (album in albums) {
|
||||
sortAlbumSongs(album)
|
||||
}
|
||||
return albums
|
||||
return songs.groupBy { it.albumId }
|
||||
.map { sortAlbumSongs(Album(it.key, it.value)) }
|
||||
}
|
||||
|
||||
private fun getOrCreateAlbum(
|
||||
albums: ArrayList<Album>,
|
||||
albumId: Int
|
||||
): Album {
|
||||
for (album in albums) {
|
||||
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) {
|
||||
return album
|
||||
private fun sortAlbumSongs(album: Album): Album {
|
||||
val songs = when (PreferenceUtil.albumDetailSongSortOrder) {
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.trackNumber.compareTo(o2.trackNumber)
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.title.compareTo(o2.title)
|
||||
}
|
||||
val album = Album()
|
||||
albums.add(album)
|
||||
return album
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||
o2.title.compareTo(o1.title)
|
||||
}
|
||||
|
||||
private fun sortAlbumSongs(album: Album) {
|
||||
when (PreferenceUtil.albumDetailSongSortOrder) {
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o1.trackNumber.compareTo(
|
||||
o2.trackNumber
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o1.title.compareTo(
|
||||
o2.title
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o2.title.compareTo(
|
||||
o1.title
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o1.duration.compareTo(
|
||||
o2.duration
|
||||
)
|
||||
})
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.duration.compareTo(o2.duration)
|
||||
}
|
||||
else -> throw IllegalArgumentException("invalid ${PreferenceUtil.albumDetailSongSortOrder}")
|
||||
}
|
||||
return album.copy(songs = songs)
|
||||
}
|
||||
|
||||
private fun getSongLoaderSortOrder(): String {
|
||||
|
|
|
@ -26,7 +26,7 @@ interface ArtistRepository {
|
|||
|
||||
fun artists(query: String): List<Artist>
|
||||
|
||||
fun artist(artistId: Int): Artist
|
||||
fun artist(artistId: Long): Artist
|
||||
}
|
||||
|
||||
class RealArtistRepository(
|
||||
|
@ -39,7 +39,29 @@ class RealArtistRepository(
|
|||
PreferenceUtil.artistAlbumSortOrder + ", " +
|
||||
PreferenceUtil.artistSongSortOrder
|
||||
}
|
||||
override fun artist(artistId: Long): Artist {
|
||||
if (artistId == Artist.VARIOUS_ARTISTS_ID) {
|
||||
// Get Various Artists
|
||||
val songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
null,
|
||||
null,
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
val albums = albumRepository.splitIntoAlbums(songs).filter { it.albumArtist == Artist.VARIOUS_ARTISTS_DISPLAY_NAME }
|
||||
return Artist(Artist.VARIOUS_ARTISTS_ID, albums)
|
||||
}
|
||||
|
||||
val songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
arrayOf(artistId.toString()),
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return Artist(artistId, albumRepository.splitIntoAlbums(songs))
|
||||
}
|
||||
override fun artists(): List<Artist> {
|
||||
val songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
|
@ -50,17 +72,6 @@ class RealArtistRepository(
|
|||
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> {
|
||||
val songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
|
@ -70,54 +81,41 @@ class RealArtistRepository(
|
|||
)
|
||||
)
|
||||
|
||||
val sortString = if (PreferenceUtil.artistSortOrder.contains("DESC")) String.CASE_INSENSITIVE_ORDER.reversed() else String.CASE_INSENSITIVE_ORDER
|
||||
|
||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs)).sortedWith(compareBy(sortString) { it.name })
|
||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
}
|
||||
|
||||
private fun splitIntoAlbumArtists(albums: List<Album>): 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 {
|
||||
override fun artists(query: String): List<Artist> {
|
||||
val songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
arrayOf(artistId.toString()),
|
||||
AudioColumns.ARTIST + " LIKE ?",
|
||||
arrayOf("%$query%"),
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return Artist(ArrayList(albumRepository.splitIntoAlbums(songs)))
|
||||
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||
}
|
||||
|
||||
fun splitIntoArtists(albums: List<Album>?): List<Artist> {
|
||||
val artists = mutableListOf<Artist>()
|
||||
if (albums != null) {
|
||||
for (album in albums) {
|
||||
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||
|
||||
private fun splitIntoAlbumArtists(albums: List<Album>): List<Artist> {
|
||||
return albums.groupBy { it.albumArtist }
|
||||
.map {
|
||||
val currentAlbums = it.value
|
||||
if (currentAlbums.isNotEmpty()) {
|
||||
if (currentAlbums[0].albumArtist == Artist.VARIOUS_ARTISTS_DISPLAY_NAME) {
|
||||
Artist(Artist.VARIOUS_ARTISTS_ID, currentAlbums)
|
||||
} else {
|
||||
Artist(currentAlbums[0].artistId, currentAlbums)
|
||||
}
|
||||
} else {
|
||||
Artist.empty
|
||||
}
|
||||
}
|
||||
return artists
|
||||
}
|
||||
|
||||
private fun getOrCreateArtist(artists: MutableList<Artist>, artistId: Int): Artist {
|
||||
for (artist in artists) {
|
||||
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
|
||||
return artist
|
||||
}
|
||||
}
|
||||
val album = Artist()
|
||||
artists.add(album)
|
||||
return album
|
||||
|
||||
|
||||
fun splitIntoArtists(albums: List<Album>): List<Artist> {
|
||||
return albums.groupBy { it.artistId }
|
||||
.map { Artist(it.key, it.value) }
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ import android.provider.MediaStore
|
|||
import android.provider.MediaStore.Audio.Genres
|
||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||
import code.name.monkey.retromusic.Constants.baseProjection
|
||||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.extensions.getString
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
|
@ -29,7 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
|||
interface GenreRepository {
|
||||
fun genres(): List<Genre>
|
||||
|
||||
fun songs(genreId: Int): List<Song>
|
||||
fun songs(genreId: Long): List<Song>
|
||||
}
|
||||
|
||||
class RealGenreRepository(
|
||||
|
@ -41,25 +43,25 @@ class RealGenreRepository(
|
|||
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,
|
||||
// so we need to get songs without a genre a different way.
|
||||
return if (genreId == -1) {
|
||||
return if (genreId == -1L) {
|
||||
getSongsWithNoGenre()
|
||||
} else songRepository.songs(makeGenreSongCursor(genreId))
|
||||
}
|
||||
|
||||
private fun getGenreFromCursor(cursor: Cursor): Genre {
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
val id = cursor.getLong(Genres._ID)
|
||||
val name = cursor.getString(Genres.NAME)
|
||||
val songCount = songs(id).size
|
||||
return Genre(id, name, songCount)
|
||||
|
||||
}
|
||||
|
||||
private fun getGenreFromCursorWithOutSongs(cursor: Cursor): Genre {
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
val id = cursor.getLong(Genres._ID)
|
||||
val name = cursor.getString(Genres.NAME)
|
||||
return Genre(id, name, -1)
|
||||
}
|
||||
|
||||
|
@ -91,9 +93,9 @@ class RealGenreRepository(
|
|||
)
|
||||
}
|
||||
|
||||
private fun makeGenreSongCursor(genreId: Int): Cursor? {
|
||||
private fun makeGenreSongCursor(genreId: Long): Cursor? {
|
||||
return contentResolver.query(
|
||||
Genres.Members.getContentUri("external", genreId.toLong()),
|
||||
Genres.Members.getContentUri("external", genreId),
|
||||
baseProjection,
|
||||
IS_MUSIC,
|
||||
null,
|
||||
|
|
|
@ -18,8 +18,14 @@ import android.content.ContentResolver
|
|||
import android.database.Cursor
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import android.provider.MediaStore.Audio.Playlists.*
|
||||
import android.provider.MediaStore.Audio.PlaylistsColumns
|
||||
import code.name.monkey.retromusic.Constants
|
||||
import code.name.monkey.retromusic.extensions.getInt
|
||||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.extensions.getString
|
||||
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.PlaylistSong
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
@ -40,11 +46,11 @@ interface PlaylistRepository {
|
|||
|
||||
fun favoritePlaylist(playlistName: String): List<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(
|
||||
|
@ -52,19 +58,20 @@ class RealPlaylistRepository(
|
|||
) : PlaylistRepository {
|
||||
|
||||
override fun playlist(cursor: Cursor?): Playlist {
|
||||
var playlist = Playlist()
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
playlist = getPlaylistFromCursorImpl(cursor)
|
||||
return cursor.use {
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
getPlaylistFromCursorImpl(cursor)
|
||||
} else {
|
||||
Playlist.empty
|
||||
}
|
||||
}
|
||||
cursor?.close()
|
||||
return playlist
|
||||
}
|
||||
|
||||
override fun playlist(playlistName: String): Playlist {
|
||||
return playlist(makePlaylistCursor(PlaylistsColumns.NAME + "=?", arrayOf(playlistName)))
|
||||
}
|
||||
|
||||
override fun playlist(playlistId: Int): Playlist {
|
||||
override fun playlist(playlistId: Long): Playlist {
|
||||
return playlist(
|
||||
makePlaylistCursor(
|
||||
BaseColumns._ID + "=?",
|
||||
|
@ -101,8 +108,8 @@ class RealPlaylistRepository(
|
|||
)
|
||||
}
|
||||
|
||||
override fun deletePlaylist(playlistId: Int) {
|
||||
val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI
|
||||
override fun deletePlaylist(playlistId: Long) {
|
||||
val localUri = EXTERNAL_CONTENT_URI
|
||||
val localStringBuilder = StringBuilder()
|
||||
localStringBuilder.append("_id IN (")
|
||||
localStringBuilder.append(playlistId)
|
||||
|
@ -113,12 +120,12 @@ class RealPlaylistRepository(
|
|||
private fun getPlaylistFromCursorImpl(
|
||||
cursor: Cursor
|
||||
): Playlist {
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
val id = cursor.getLong(MediaStore.MediaColumns._ID)
|
||||
val name = cursor.getString(NAME)
|
||||
return Playlist(id, name)
|
||||
}
|
||||
|
||||
override fun playlistSongs(playlistId: Int): List<Song> {
|
||||
override fun playlistSongs(playlistId: Long): List<Song> {
|
||||
val songs = arrayListOf<Song>()
|
||||
val cursor = makePlaylistSongCursor(playlistId)
|
||||
|
||||
|
@ -131,21 +138,21 @@ class RealPlaylistRepository(
|
|||
return songs
|
||||
}
|
||||
|
||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
val idInPlaylist = cursor.getInt(11)
|
||||
val composer = cursor.getString(12)
|
||||
val albumArtist = cursor.getString(13)
|
||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
|
||||
val id = cursor.getLong(Members.AUDIO_ID)
|
||||
val title = cursor.getString(AudioColumns.TITLE)
|
||||
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||
val year = cursor.getInt(AudioColumns.YEAR)
|
||||
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||
val data = cursor.getString(AudioColumns.DATA)
|
||||
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||
val albumName = cursor.getString(AudioColumns.ALBUM)
|
||||
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||
val artistName = cursor.getString(AudioColumns.ARTIST)
|
||||
val idInPlaylist = cursor.getLong(Members._ID)
|
||||
val composer = cursor.getStringOrNull(AudioColumns.COMPOSER)
|
||||
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||
return PlaylistSong(
|
||||
id,
|
||||
title,
|
||||
|
@ -160,7 +167,7 @@ class RealPlaylistRepository(
|
|||
artistName,
|
||||
playlistId,
|
||||
idInPlaylist,
|
||||
composer,
|
||||
composer ?: "",
|
||||
albumArtist
|
||||
)
|
||||
}
|
||||
|
@ -170,37 +177,37 @@ class RealPlaylistRepository(
|
|||
values: Array<String>?
|
||||
): Cursor? {
|
||||
return contentResolver.query(
|
||||
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
BaseColumns._ID, /* 0 */
|
||||
PlaylistsColumns.NAME /* 1 */
|
||||
),
|
||||
selection,
|
||||
values,
|
||||
MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER
|
||||
DEFAULT_SORT_ORDER
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun makePlaylistSongCursor(playlistId: Int): Cursor? {
|
||||
private fun makePlaylistSongCursor(playlistId: Long): Cursor? {
|
||||
return contentResolver.query(
|
||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()),
|
||||
Members.getContentUri("external", playlistId),
|
||||
arrayOf(
|
||||
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0
|
||||
MediaStore.Audio.AudioColumns.TITLE, // 1
|
||||
MediaStore.Audio.AudioColumns.TRACK, // 2
|
||||
MediaStore.Audio.AudioColumns.YEAR, // 3
|
||||
MediaStore.Audio.AudioColumns.DURATION, // 4
|
||||
MediaStore.Audio.AudioColumns.DATA, // 5
|
||||
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
|
||||
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
|
||||
MediaStore.Audio.AudioColumns.ALBUM, // 8
|
||||
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
||||
MediaStore.Audio.AudioColumns.ARTIST, // 10
|
||||
MediaStore.Audio.Playlists.Members._ID,//11
|
||||
MediaStore.Audio.AudioColumns.COMPOSER,//12
|
||||
Members.AUDIO_ID, // 0
|
||||
AudioColumns.TITLE, // 1
|
||||
AudioColumns.TRACK, // 2
|
||||
AudioColumns.YEAR, // 3
|
||||
AudioColumns.DURATION, // 4
|
||||
AudioColumns.DATA, // 5
|
||||
AudioColumns.DATE_MODIFIED, // 6
|
||||
AudioColumns.ALBUM_ID, // 7
|
||||
AudioColumns.ALBUM, // 8
|
||||
AudioColumns.ARTIST_ID, // 9
|
||||
AudioColumns.ARTIST, // 10
|
||||
Members._ID,//11
|
||||
AudioColumns.COMPOSER,//12
|
||||
"album_artist"//13
|
||||
), Constants.IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
||||
), Constants.IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,12 @@ import android.content.Context
|
|||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import android.provider.MediaStore.Audio.Playlists.*
|
||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||
import code.name.monkey.retromusic.extensions.getInt
|
||||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.extensions.getString
|
||||
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.PlaylistSong
|
||||
|
@ -42,7 +47,7 @@ object PlaylistSongsLoader {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPlaylistSongList(context: Context, playlistId: Int): List<Song> {
|
||||
fun getPlaylistSongList(context: Context, playlistId: Long): List<Song> {
|
||||
val songs = mutableListOf<Song>()
|
||||
val cursor =
|
||||
makePlaylistSongCursor(
|
||||
|
@ -64,21 +69,22 @@ object PlaylistSongsLoader {
|
|||
return songs
|
||||
}
|
||||
|
||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Int): PlaylistSong {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
val idInPlaylist = cursor.getInt(11)
|
||||
val composer = cursor.getString(12)
|
||||
val albumArtist = cursor.getString(13)
|
||||
// TODO duplicated in [PlaylistRepository.kt]
|
||||
private fun getPlaylistSongFromCursorImpl(cursor: Cursor, playlistId: Long): PlaylistSong {
|
||||
val id = cursor.getLong(Members.AUDIO_ID)
|
||||
val title = cursor.getString(AudioColumns.TITLE)
|
||||
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||
val year = cursor.getInt(AudioColumns.YEAR)
|
||||
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||
val data = cursor.getString(AudioColumns.DATA)
|
||||
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||
val albumName = cursor.getString(AudioColumns.ALBUM)
|
||||
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||
val artistName = cursor.getString(AudioColumns.ARTIST)
|
||||
val idInPlaylist = cursor.getLong(Members._ID)
|
||||
val composer = cursor.getString(AudioColumns.COMPOSER)
|
||||
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||
return PlaylistSong(
|
||||
id,
|
||||
title,
|
||||
|
@ -98,12 +104,12 @@ object PlaylistSongsLoader {
|
|||
)
|
||||
}
|
||||
|
||||
private fun makePlaylistSongCursor(context: Context, playlistId: Int): Cursor? {
|
||||
private fun makePlaylistSongCursor(context: Context, playlistId: Long): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()),
|
||||
Members.getContentUri("external", playlistId),
|
||||
arrayOf(
|
||||
MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0
|
||||
Members.AUDIO_ID, // 0
|
||||
AudioColumns.TITLE, // 1
|
||||
AudioColumns.TRACK, // 2
|
||||
AudioColumns.YEAR, // 3
|
||||
|
@ -114,10 +120,10 @@ object PlaylistSongsLoader {
|
|||
AudioColumns.ALBUM, // 8
|
||||
AudioColumns.ARTIST_ID, // 9
|
||||
AudioColumns.ARTIST, // 10
|
||||
MediaStore.Audio.Playlists.Members._ID,//11
|
||||
Members._ID,//11
|
||||
AudioColumns.COMPOSER,//12
|
||||
"album_artist"//13
|
||||
), IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
||||
), IS_MUSIC, null, Members.DEFAULT_SORT_ORDER
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
|
|
|
@ -41,10 +41,10 @@ interface Repository {
|
|||
fun historySong(): List<HistoryEntity>
|
||||
fun favorites(): LiveData<List<SongEntity>>
|
||||
fun observableHistorySongs(): LiveData<List<HistoryEntity>>
|
||||
fun albumById(albumId: Int): Album
|
||||
fun albumById(albumId: Long): Album
|
||||
fun playlistSongs(playlistEntity: PlaylistEntity): LiveData<List<SongEntity>>
|
||||
suspend fun fetchAlbums(): List<Album>
|
||||
suspend fun albumByIdAsync(albumId: Int): Album
|
||||
suspend fun albumByIdAsync(albumId: Long): Album
|
||||
suspend fun allSongs(): List<Song>
|
||||
suspend fun fetchArtists(): List<Artist>
|
||||
suspend fun albumArtists(): List<Artist>
|
||||
|
@ -52,10 +52,10 @@ interface Repository {
|
|||
suspend fun fetchGenres(): List<Genre>
|
||||
suspend fun search(query: String?): MutableList<Any>
|
||||
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 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 topArtists(): List<Artist>
|
||||
suspend fun topAlbums(): List<Album>
|
||||
|
@ -70,7 +70,7 @@ interface Repository {
|
|||
suspend fun playlists(): Home
|
||||
suspend fun homeSections(): 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 playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
|
||||
suspend fun insertSongs(songs: List<SongEntity>)
|
||||
|
@ -78,7 +78,7 @@ interface Repository {
|
|||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||
suspend fun fetchPlaylists(): 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 removeSongFromPlaylist(songEntity: SongEntity)
|
||||
suspend fun deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
||||
|
@ -93,7 +93,7 @@ interface Repository {
|
|||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
||||
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 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 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()
|
||||
|
||||
|
@ -160,7 +160,7 @@ class RealRepository(
|
|||
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(
|
||||
name: String,
|
||||
|
@ -235,7 +235,7 @@ class RealRepository(
|
|||
}
|
||||
|
||||
|
||||
override suspend fun playlist(playlistId: Int) =
|
||||
override suspend fun playlist(playlistId: Long) =
|
||||
playlistRepository.playlist(playlistId)
|
||||
|
||||
override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> =
|
||||
|
@ -263,7 +263,7 @@ class RealRepository(
|
|||
override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) =
|
||||
roomRepository.deletePlaylistEntities(playlists)
|
||||
|
||||
override suspend fun renameRoomPlaylist(playlistId: Int, name: String) =
|
||||
override suspend fun renameRoomPlaylist(playlistId: Long, name: String) =
|
||||
roomRepository.renamePlaylistEntity(playlistId, name)
|
||||
|
||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
|
||||
|
@ -306,7 +306,7 @@ class RealRepository(
|
|||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
roomRepository.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||
roomRepository.checkSongExistInPlayCount(songId)
|
||||
|
||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||
|
|
|
@ -18,7 +18,7 @@ interface RoomRepository {
|
|||
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
|
||||
suspend fun insertSongs(songs: List<SongEntity>)
|
||||
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 deletePlaylistSongs(playlists: List<PlaylistEntity>)
|
||||
suspend fun favoritePlaylist(favorite: String): PlaylistEntity
|
||||
|
@ -31,7 +31,7 @@ interface RoomRepository {
|
|||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||
|
@ -76,7 +76,7 @@ class RealRoomRepository(
|
|||
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
|
||||
playlistDao.deletePlaylists(playlistEntities)
|
||||
|
||||
override suspend fun renamePlaylistEntity(playlistId: Int, name: String) =
|
||||
override suspend fun renamePlaylistEntity(playlistId: Long, name: String) =
|
||||
playlistDao.renamePlaylist(playlistId, name)
|
||||
|
||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) {
|
||||
|
@ -95,7 +95,7 @@ class RealRoomRepository(
|
|||
return if (playlist != null) {
|
||||
playlist
|
||||
} else {
|
||||
createPlaylist(PlaylistEntity(favorite))
|
||||
createPlaylist(PlaylistEntity(playlistName = favorite))
|
||||
playlistDao.isPlaylistExists(favorite).first()
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ class RealRoomRepository(
|
|||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
playCountDao.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||
playCountDao.checkSongExistInPlayCount(songId)
|
||||
|
||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||
|
|
|
@ -18,8 +18,13 @@ import android.content.Context
|
|||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import android.provider.MediaStore.Audio.Media
|
||||
import code.name.monkey.retromusic.Constants.IS_MUSIC
|
||||
import code.name.monkey.retromusic.Constants.baseProjection
|
||||
import code.name.monkey.retromusic.extensions.getInt
|
||||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.extensions.getString
|
||||
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
|
@ -40,7 +45,7 @@ interface SongRepository {
|
|||
|
||||
fun song(cursor: Cursor?): Song
|
||||
|
||||
fun song(songId: Int): Song
|
||||
fun song(songId: Long): Song
|
||||
}
|
||||
|
||||
class RealSongRepository(private val context: Context) : SongRepository {
|
||||
|
@ -74,14 +79,14 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
|||
return songs(makeSongCursor(AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%")))
|
||||
}
|
||||
|
||||
override fun song(songId: Int): Song {
|
||||
override fun song(songId: Long): Song {
|
||||
return song(makeSongCursor(AudioColumns._ID + "=?", arrayOf(songId.toString())))
|
||||
}
|
||||
|
||||
override fun songsByFilePath(filePath: String): List<Song> {
|
||||
return songs(
|
||||
makeSongCursor(
|
||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
||||
AudioColumns.DATA + "=?",
|
||||
arrayOf(filePath)
|
||||
)
|
||||
)
|
||||
|
@ -90,19 +95,19 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
|||
private fun getSongFromCursorImpl(
|
||||
cursor: Cursor
|
||||
): Song {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
val composer = cursor.getString(11)
|
||||
val albumArtist = cursor.getString(12)
|
||||
val id = cursor.getLong(AudioColumns._ID)
|
||||
val title = cursor.getString(AudioColumns.TITLE)
|
||||
val trackNumber = cursor.getInt(AudioColumns.TRACK)
|
||||
val year = cursor.getInt(AudioColumns.YEAR)
|
||||
val duration = cursor.getLong(AudioColumns.DURATION)
|
||||
val data = cursor.getString(AudioColumns.DATA)
|
||||
val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED)
|
||||
val albumId = cursor.getLong(AudioColumns.ALBUM_ID)
|
||||
val albumName = cursor.getStringOrNull(AudioColumns.ALBUM)
|
||||
val artistId = cursor.getLong(AudioColumns.ARTIST_ID)
|
||||
val artistName = cursor.getStringOrNull(AudioColumns.ARTIST)
|
||||
val composer = cursor.getStringOrNull(AudioColumns.COMPOSER)
|
||||
val albumArtist = cursor.getStringOrNull("album_artist")
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
|
@ -142,18 +147,15 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
|||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
||||
}
|
||||
selectionFinal =
|
||||
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
||||
try {
|
||||
selectionFinal + " AND " + Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
|
||||
|
||||
return context.contentResolver.query(
|
||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
|
||||
baseProjection,
|
||||
selectionFinal,
|
||||
selectionValuesFinal,
|
||||
sortOrder
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (songIndex == -1) {
|
||||
songIndex = 0
|
||||
|
|
|
@ -618,7 +618,7 @@ public class MusicService extends Service implements
|
|||
break;
|
||||
case SHUFFLE_MODE_NONE:
|
||||
this.shuffleMode = shuffleMode;
|
||||
int currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
|
||||
long currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
|
||||
playingQueue = new ArrayList<>(originalPlayingQueue);
|
||||
int newPosition = 0;
|
||||
if (getPlayingQueue() != null) {
|
||||
|
|
|
@ -34,7 +34,7 @@ public class AutoGeneratedPlaylistBitmap {
|
|||
if (songPlaylist == null) return null;
|
||||
long start = System.currentTimeMillis();
|
||||
// lấy toàn bộ album id, loại bỏ trùng nhau
|
||||
ArrayList<Integer> albumID = new ArrayList<>();
|
||||
List<Long> albumID = new ArrayList<>();
|
||||
for (Song song : songPlaylist) {
|
||||
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ public class AutoGeneratedPlaylistBitmap {
|
|||
long start2 = System.currentTimeMillis() - start;
|
||||
|
||||
// lấy toàn bộ art tồn tại
|
||||
ArrayList<Bitmap> art = new ArrayList<Bitmap>();
|
||||
for (Integer id : albumID) {
|
||||
List<Bitmap> art = new ArrayList<Bitmap>();
|
||||
for (Long id : albumID) {
|
||||
Bitmap bitmap = getBitmapWithAlbumId(context, id);
|
||||
if (bitmap != null) art.add(bitmap);
|
||||
if (art.size() == 6) break;
|
||||
|
@ -168,7 +168,7 @@ public class AutoGeneratedPlaylistBitmap {
|
|||
else return bitmap;
|
||||
}
|
||||
|
||||
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Integer id) {
|
||||
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
|
||||
try {
|
||||
return Glide.with(context)
|
||||
.load(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(id))
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.core.content.FileProvider
|
|||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
|
@ -85,7 +86,7 @@ object MusicUtil : KoinComponent {
|
|||
return albumArtDir
|
||||
}
|
||||
|
||||
fun deleteAlbumArt(context: Context, albumId: Int) {
|
||||
fun deleteAlbumArt(context: Context, albumId: Long) {
|
||||
val contentResolver = context.contentResolver
|
||||
val localUri = Uri.parse("content://media/external/audio/albumart")
|
||||
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId.toLong()), null, null)
|
||||
|
@ -175,10 +176,9 @@ object MusicUtil : KoinComponent {
|
|||
return lyrics
|
||||
}
|
||||
|
||||
fun getMediaStoreAlbumCoverUri(albumId: Int): Uri {
|
||||
val sArtworkUri =
|
||||
Uri.parse("content://media/external/audio/albumart")
|
||||
return ContentUris.withAppendedId(sArtworkUri, albumId.toLong())
|
||||
fun getMediaStoreAlbumCoverUri(albumId: Long): Uri {
|
||||
val sArtworkUri = Uri.parse("content://media/external/audio/albumart")
|
||||
return ContentUris.withAppendedId(sArtworkUri, albumId)
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,7 +249,7 @@ object MusicUtil : KoinComponent {
|
|||
return "$songCount $songString"
|
||||
}
|
||||
|
||||
fun getSongFileUri(songId: Int): Uri {
|
||||
fun getSongFileUri(songId: Long): Uri {
|
||||
return ContentUris.withAppendedId(
|
||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
songId.toLong()
|
||||
|
@ -268,18 +268,13 @@ object MusicUtil : KoinComponent {
|
|||
return if (year > 0) year.toString() else "-"
|
||||
}
|
||||
|
||||
fun indexOfSongInList(songs: List<Song>, songId: Int): Int {
|
||||
for (i in songs.indices) {
|
||||
if (songs[i].id == songId) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
fun indexOfSongInList(songs: List<Song>, songId: Long): Int {
|
||||
return songs.indexOfFirst { it.id == songId }
|
||||
}
|
||||
|
||||
fun insertAlbumArt(
|
||||
context: Context,
|
||||
albumId: Int,
|
||||
albumId: Long,
|
||||
path: String?
|
||||
) {
|
||||
val contentResolver = context.contentResolver
|
||||
|
@ -304,9 +299,19 @@ object MusicUtil : KoinComponent {
|
|||
return tempName == "unknown" || tempName == "<unknown>"
|
||||
}
|
||||
|
||||
fun isVariousArtists(artistName: String?): Boolean {
|
||||
if (TextUtils.isEmpty(artistName)) {
|
||||
return false
|
||||
}
|
||||
if (artistName == Artist.VARIOUS_ARTISTS_DISPLAY_NAME) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun isFavorite(context: Context, song: Song): Boolean {
|
||||
return PlaylistsUtil
|
||||
.doPlaylistContains(context, getFavoritesPlaylist(context).id.toLong(), song.id)
|
||||
.doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id)
|
||||
}
|
||||
|
||||
fun isFavoritePlaylist(
|
||||
|
@ -387,7 +392,7 @@ object MusicUtil : KoinComponent {
|
|||
// as from the album art cache
|
||||
cursor.moveToFirst()
|
||||
while (!cursor.isAfterLast) {
|
||||
val id = cursor.getInt(0)
|
||||
val id = cursor.getLong(BaseColumns._ID)
|
||||
val song: Song = songRepository.song(id)
|
||||
removeFromQueue(song)
|
||||
cursor.moveToNext()
|
||||
|
@ -452,7 +457,7 @@ object MusicUtil : KoinComponent {
|
|||
// as from the album art cache
|
||||
cursor.moveToFirst()
|
||||
while (!cursor.isAfterLast) {
|
||||
val id: Int = cursor.getInt(0)
|
||||
val id = cursor.getLong(BaseColumns._ID)
|
||||
val song: Song = RealSongRepository(context).song(id)
|
||||
removeFromQueue(song)
|
||||
cursor.moveToNext()
|
||||
|
|
|
@ -43,7 +43,7 @@ import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
|||
|
||||
public class PlaylistsUtil {
|
||||
|
||||
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
||||
public static long createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
||||
int id = -1;
|
||||
if (name != null && name.length() > 0) {
|
||||
try {
|
||||
|
@ -101,13 +101,13 @@ public class PlaylistsUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addToPlaylist(@NonNull final Context context, final Song song, final int playlistId, final boolean showToastOnFinish) {
|
||||
public static void addToPlaylist(@NonNull final Context context, final Song song, final long playlistId, final boolean showToastOnFinish) {
|
||||
List<Song> helperList = new ArrayList<>();
|
||||
helperList.add(song);
|
||||
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 ContentResolver resolver = context.getContentResolver();
|
||||
final String[] projection = new String[]{
|
||||
|
@ -180,7 +180,7 @@ public class PlaylistsUtil {
|
|||
return "";
|
||||
}
|
||||
|
||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) {
|
||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, long playlistId) {
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||
"external", playlistId);
|
||||
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
|
||||
|
@ -193,7 +193,7 @@ public class PlaylistsUtil {
|
|||
}
|
||||
|
||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
|
||||
final int playlistId = songs.get(0).getPlaylistId();
|
||||
final long playlistId = songs.get(0).getPlaylistId();
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||
"external", playlistId);
|
||||
String[] selectionArgs = new String[songs.size()];
|
||||
|
@ -211,7 +211,7 @@ public class PlaylistsUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) {
|
||||
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final long songId) {
|
||||
if (playlistId != -1) {
|
||||
try {
|
||||
Cursor c = context.getContentResolver().query(
|
||||
|
@ -229,7 +229,7 @@ public class PlaylistsUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) {
|
||||
public static boolean moveItem(@NonNull final Context context, long playlistId, int from, int to) {
|
||||
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
|
||||
playlistId, from, to);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:orientation="vertical"
|
||||
android:transitionName="@string/transition_album_art"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<FrameLayout
|
||||
|
@ -46,9 +47,7 @@
|
|||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:transitionName="@string/transition_album_art"
|
||||
app:cardCornerRadius="24dp"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/container"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
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
|
||||
android:id="@+id/appBarLayout"
|
||||
|
@ -48,7 +49,6 @@
|
|||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:transitionName="@string/transition_album_art"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
android:transitionGroup="true"
|
||||
android:scrollbars="none"
|
||||
app:layout_dodgeInsetEdges="bottom"
|
||||
tools:listitem="@layout/item_list" />
|
||||
|
|
|
@ -41,9 +41,5 @@
|
|||
android:label=""
|
||||
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>
|
|
@ -32,7 +32,7 @@
|
|||
tools:layout="@layout/fragment_album_details">
|
||||
<argument
|
||||
android:name="extra_album_id"
|
||||
app:argType="integer" />
|
||||
app:argType="long" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -42,7 +42,7 @@
|
|||
tools:layout="@layout/fragment_artist_details">
|
||||
<argument
|
||||
android:name="extra_artist_id"
|
||||
app:argType="integer" />
|
||||
app:argType="long" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<item name="action_album_sort_order_desc" type="id" />
|
||||
<item name="action_album_sort_order_artist" 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_desc" type="id" />
|
||||
<item name="action_song_sort_order_asc" type="id" />
|
||||
|
|
Loading…
Reference in a new issue