This commit is contained in:
h4h13 2020-02-05 17:14:22 +05:30
parent 016c7f6218
commit b922549dee
37 changed files with 606 additions and 693 deletions

View file

@ -27,14 +27,15 @@ import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView
import code.name.monkey.retromusic.rest.model.LastFmAlbum
@ -62,7 +63,6 @@ import kotlinx.android.synthetic.main.activity_album_content.scrobbles
import kotlinx.android.synthetic.main.activity_album_content.scrobblesLabel
import kotlinx.android.synthetic.main.activity_album_content.shuffleAction
import kotlinx.android.synthetic.main.activity_album_content.songTitle
import java.util.ArrayList
import javax.inject.Inject
import android.util.Pair as UtilPair
@ -124,7 +124,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
albumDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let {
intent.extras?.getLong(EXTRA_ALBUM_ID)?.let {
albumDetailsPresenter.loadAlbum(it)
albumCoverContainer?.transitionName = "${getString(R.string.transition_album_art)}_$it"
}
@ -151,10 +151,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
}
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
//setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
//setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
}
aboutAlbumText.setOnClickListener {
@ -187,37 +187,32 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
override fun album(album: Album) {
complete()
if (album.songs!!.isEmpty()) {
/*if (album.songs!!.isEmpty()) {
finish()
return
}
}*/
this.album = album
albumTitle.text = album.title
if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format(
"%s • %s",
album.artistName,
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
albumText.text = String.format("%s", album.artist)
} else {
albumText.text = String.format(
"%s • %s • %s",
album.artistName,
MusicUtil.getYearString(album.year),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
albumText.text = String.format("%s • %s", album.artist, MusicUtil.getYearString(album.year))
}
loadAlbumCover()
simpleSongAdapter.swapDataSet(album.songs)
albumDetailsPresenter.albumSong(album.id)
albumDetailsPresenter.loadMore(album.artistId)
albumDetailsPresenter.aboutAlbum(album.artistName!!, album.title!!)
albumDetailsPresenter.aboutAlbum(album.artist, album.title)
}
override fun songs(songs: ArrayList<Song>) {
simpleSongAdapter.swapDataSet(songs)
}
override fun moreAlbums(albums: ArrayList<Album>) {
moreTitle.show()
moreRecyclerView.show()
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
moreTitle.text = String.format(getString(R.string.label_more_from), album.artist)
val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
moreRecyclerView.layoutManager = GridLayoutManager(
@ -250,19 +245,23 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
}
override fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
.dontAnimate().dontTransform().into(object : RetroMusicColoredTarget(artistImage) {
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
.generatePalette(this)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(color: Int) {
}
})
}
private fun loadAlbumCover() {
SongGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
.checkIgnoreMediaStore(this)
.ignoreMediaStore(PreferenceUtil.getInstance(this).ignoreMediaStoreArtwork())
AlbumGlideRequest.Builder(Glide.with(this), album.id)
.generatePalette(this)
.build().dontAnimate().dontTransform()
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(color: Int) {
setColors(color)
@ -383,7 +382,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
intent.extras?.getLong(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}

View file

@ -22,14 +22,14 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView
import code.name.monkey.retromusic.rest.model.LastFmArtist
@ -118,7 +118,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
artistDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let {
intent.extras?.getLong(EXTRA_ARTIST_ID)?.let {
artistDetailsPresenter.loadArtist(it)
val name = "${getString(R.string.transition_artist_image)}_$it"
artistCoverContainer?.transitionName = name
@ -133,10 +133,10 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
setupRecyclerView()
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
//setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
//setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
biographyText.setOnClickListener {
@ -189,6 +189,14 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
ActivityCompat.startPostponedEnterTransition(this)
}
override fun songs(songs: ArrayList<Song>) {
songAdapter.swapDataSet(songs)
}
override fun albums(albums: List<Album>) {
albumAdapter.swapDataSet(ArrayList(albums))
}
override fun artist(artist: Artist) {
complete()
if (artist.songCount <= 0) {
@ -202,13 +210,12 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
}
artistTitle.text = artist.name
text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(this, artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
"%s",
MusicUtil.getArtistInfoString(this, artist)
)
songAdapter.swapDataSet(artist.songs)
albumAdapter.swapDataSet(artist.albums!!)
artistDetailsPresenter.loadArtistAlbums(artist.id)
artistDetailsPresenter.loadArtistSongs(artist.id)
//albumAdapter.swapDataSet(artist.albums!!)
}
private fun loadBiography(
@ -304,22 +311,22 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
//val songs = artist.songs
when (item.itemId) {
android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
//MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
//MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
//AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_set_artist_image -> {
@ -354,7 +361,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
intent.extras?.getLong(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else {
finish()
}

View file

@ -19,8 +19,6 @@ import code.name.monkey.retromusic.fragments.mainactivity.home.BannerHomeFragmen
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.loaders.ArtistLoader
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater
@ -155,14 +153,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
//MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true
}
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
//MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
handled = true
}
}

View file

@ -19,7 +19,6 @@ import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.rest.LastFMRestClient
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
@ -39,7 +38,6 @@ import kotlinx.android.synthetic.main.activity_album_tag_editor.toolbar
import kotlinx.android.synthetic.main.activity_album_tag_editor.yearContainer
import kotlinx.android.synthetic.main.activity_album_tag_editor.yearTitle
import org.jaudiotagger.tag.FieldKey
import java.util.ArrayList
import java.util.EnumMap
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
@ -183,12 +181,13 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
}
override fun getSongPaths(): List<String> {
val songs = AlbumLoader.getAlbum(this, id).songs
val paths = ArrayList<String>(songs!!.size)
for (song in songs) {
paths.add(song.data)
}
return paths
//val songs = AlbumLoader.getAlbum(this, id).songs
//val paths = ArrayList<String>(songs!!.size)
//for (song in songs) {
// paths.add(song.data)
//}
//return paths
return emptyList()
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {

View file

@ -10,7 +10,6 @@ import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
@ -60,9 +59,9 @@ class SearchAdapter(
ALBUM -> {
val album = dataSet?.get(position) as Album
holder.title?.text = album.title
holder.text?.text = album.artistName
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build().into(holder.image)
holder.text?.text = album.artist
/*SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build().into(holder.image)*/
}
ARTIST -> {
val artist = dataSet?.get(position) as Artist

View file

@ -2,7 +2,6 @@ package code.name.monkey.retromusic.adapter.album
import android.app.ActivityOptions
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
@ -13,9 +12,8 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
@ -29,7 +27,7 @@ import me.zhanghai.android.fastscroll.PopupTextProvider
open class AlbumAdapter(
protected val activity: AppCompatActivity,
dataSet: ArrayList<Album>,
dataSet: List<Album>,
protected var itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?
@ -39,7 +37,7 @@ open class AlbumAdapter(
R.menu.menu_media_selection
), PopupTextProvider {
var dataSet: ArrayList<Album>
var dataSet: List<Album>
protected set
protected var usePalette = false
@ -60,7 +58,7 @@ open class AlbumAdapter(
notifyDataSetChanged()
}
fun swapDataSet(dataSet: ArrayList<Album>) {
fun swapDataSet(dataSet: List<Album>) {
this.dataSet = dataSet
notifyDataSetChanged()
}
@ -79,7 +77,7 @@ open class AlbumAdapter(
}
protected open fun getAlbumText(album: Album): String? {
return album.artistName
return album.artist
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@ -89,13 +87,13 @@ open class AlbumAdapter(
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs?.let { songs ->
/*album.songs?.let { songs ->
MusicPlayerRemote.openQueue(
songs,
0,
true
)
}
}*/
}
loadAlbumCover(album, holder)
}
@ -123,15 +121,12 @@ open class AlbumAdapter(
if (holder.image == null) {
return
}
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).generatePalette(activity).build()
AlbumGlideRequest.Builder(Glide.with(activity), album.id)
.generatePalette(activity)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(defaultFooterColor, holder)
}
override fun onColorReady(color: Int) {
setColors(color, holder)
}
@ -143,7 +138,7 @@ open class AlbumAdapter(
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong()
return dataSet[position].id
}
override fun getIdentifier(position: Int): Album? {
@ -163,7 +158,7 @@ open class AlbumAdapter(
private fun getSongList(albums: List<Album>): ArrayList<Song> {
val songs = ArrayList<Song>()
for (album in albums) {
songs.addAll(album.songs!!)
//songs.addAll(album.songs!!)
}
return songs
}
@ -177,7 +172,7 @@ open class AlbumAdapter(
when (PreferenceUtil.getInstance(activity).albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName =
dataSet[position].title
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artist
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
dataSet[position].year
)

View file

@ -22,9 +22,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.views.MetalRecyclerViewPager
@ -47,13 +46,13 @@ class AlbumFullWidthAdapter(
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs?.let { songs ->
/*album.songs?.let { songs ->
MusicPlayerRemote.openQueue(
songs,
0,
true
)
}
}*/
}
loadAlbumCover(album, holder)
}
@ -63,21 +62,32 @@ class AlbumFullWidthAdapter(
}
private fun getAlbumText(album: Album): String? {
return album.artistName
return album.artist
}
private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) {
if (holder.image == null) {
return
}
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
AlbumGlideRequest.Builder(Glide.with(activity), album.id)
.generatePalette(activity)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(color: Int) {
}
})
/*SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity)
.generatePalette(activity)
.build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(color: Int) {
}
})
})*/
}
override fun getItemCount(): Int {

View file

@ -1,12 +1,11 @@
package code.name.monkey.retromusic.adapter.album
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album
@ -36,7 +35,17 @@ class HorizontalAlbumAdapter(
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
if (holder.image == null) return
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
AlbumGlideRequest.Builder(Glide.with(activity), album.id)
.generatePalette(activity)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(color: Int) {
//setColors(color, holder)
}
})
/*SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).generatePalette(activity).build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
@ -48,7 +57,7 @@ class HorizontalAlbumAdapter(
if (usePalette) setColors(color, holder)
else setColors(albumArtistFooterColor, holder)
}
})
})*/
}
override fun getAlbumText(album: Album): String? {

View file

@ -121,7 +121,7 @@ class ArtistAdapter(
private fun getSongList(artists: List<Artist>): ArrayList<Song> {
val songs = ArrayList<Song>()
for (artist in artists) {
songs.addAll(artist.songs) // maybe async in future?
//songs.addAll(artist.songs) // maybe async in future?
}
return songs
}

View file

@ -63,7 +63,7 @@ open class PlaylistSongAdapter(
imageContainerCard ?: image,
"${activity.getString(R.string.transition_album_art)}_${song.albumId}"
)
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
NavigationUtil.goToAlbumOptions(activity, song.albumId.toLong(), activityOptions)
return true
}
return super.onSongMenuItemClick(item)

View file

@ -177,7 +177,7 @@ open class SongAdapter(
imageContainerCard ?: image,
"${activity.getString(R.string.transition_album_art)}_${song.albumId}"
)
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
NavigationUtil.goToAlbumOptions(activity, song.albumId.toLong(), activityOptions)
return true
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020 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.extensions
import android.database.Cursor
/**
* Created by hemanths on 2020-02-05.
*/
fun Cursor?.forEach(
closeAfter: Boolean = false,
each: Cursor.() -> Unit
) {
if (this == null) return
if (moveToFirst()) {
do {
each(this)
} while (moveToNext())
}
if (closeAfter) {
close()
}
}
fun <T> Cursor?.mapList(
closeAfter: Boolean = false,
mapper: Cursor.() -> T
): MutableList<T> {
val result = mutableListOf<T>()
forEach(closeAfter = closeAfter) {
result.add(mapper(this))
}
return result
}

View file

@ -111,7 +111,7 @@ abstract class AbsPlayerFragment : AbsMusicServiceFragment(),
return true
}
R.id.action_go_to_artist -> {
NavigationUtil.goToArtist(requireActivity(), song.artistId)
NavigationUtil.goToArtist(requireActivity(), song.artistId.toInt())
return true
}
R.id.now_playing -> {

View file

@ -41,7 +41,7 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Al
albumsPresenter.detachView()
}
override fun albums(albums: java.util.ArrayList<Album>) {
override fun albums(albums: List<Album>) {
adapter?.swapDataSet(albums)
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2020 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.glide
import android.R.anim
import android.content.Context
import code.name.monkey.retromusic.R.drawable
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.BitmapRequestBuilder
import com.bumptech.glide.DrawableTypeRequest
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.Key
import com.bumptech.glide.load.engine.DiskCacheStrategy.NONE
import com.bumptech.glide.signature.MediaStoreSignature
/**
* Created by hemanths on 2020-02-05.
*/
class AlbumGlideRequest {
companion object {
private val DEFAULT_DISK_CACHE_STRATEGY = NONE
private const val DEFAULT_ERROR_IMAGE = drawable.default_album_art
private const val DEFAULT_ANIMATION = anim.fade_in
private fun createBaseRequest(
requestManager: RequestManager,
albumId: Long
): DrawableTypeRequest<*> =
requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(albumId))
private fun createSignature(albumId: Long): Key? {
return MediaStoreSignature("", albumId, 0)
}
}
class Builder(val requestManager: RequestManager, val albumId: Long) {
fun from(requestManager: RequestManager, albumId: Long): Builder {
return Builder(requestManager, albumId)
}
fun generatePalette(context: Context): PaletteBuilder {
return PaletteBuilder(this, context)
}
}
class PaletteBuilder(private val builder: Builder, private val context: Context) {
fun build(): BitmapRequestBuilder<out Any, BitmapPaletteWrapper> =
createBaseRequest(builder.requestManager, builder.albumId)
.asBitmap()
.transcode(BitmapPaletteTranscoder(context), BitmapPaletteWrapper::class.java)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
.signature(createSignature(builder.albumId))
}
}

View file

@ -91,7 +91,7 @@ object SongMenuHelper {
return true
}
R.id.action_go_to_artist -> {
NavigationUtil.goToArtist(activity, song.artistId)
NavigationUtil.goToArtist(activity, song.artistId.toInt())
return true
}
}

View file

@ -15,13 +15,16 @@
package code.name.monkey.retromusic.loaders
import android.content.Context
import android.provider.MediaStore.Audio.AudioColumns
import android.database.Cursor
import android.provider.BaseColumns
import android.provider.MediaStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.extensions.mapList
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
import java.util.*
import kotlin.collections.ArrayList
import android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI as SONGS_URI
/**
* Created by hemanths on 11/08/17.
@ -29,75 +32,88 @@ import kotlin.collections.ArrayList
object AlbumLoader {
fun getAlbums(
context: Context,
query: String
): ArrayList<Album> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
AudioColumns.ALBUM + " LIKE ?",
arrayOf("%$query%"),
getSongLoaderSortOrder(context))
)
return splitIntoAlbums(songs)
}
fun getAlbum(
context: Context,
albumId: Int
): Album {
val songs = SongLoader.getSongs(
SongLoader.makeSongCursor(
context,
AudioColumns.ALBUM_ID + "=?",
arrayOf(albumId.toString()),
getSongLoaderSortOrder(context)))
val album = Album(songs)
sortSongsByTrackNumber(album)
return album
}
fun getAllAlbums(
context: Context
): ArrayList<Album> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, null, null, getSongLoaderSortOrder(context)))
return splitIntoAlbums(songs)
}
fun splitIntoAlbums(
songs: ArrayList<Song>?
): ArrayList<Album> {
val albums = ArrayList<Album>()
if (songs != null) {
for (song in songs) {
getOrCreateAlbum(albums, song.albumId).songs?.add(song)
fun getAllAlbums(context: Context): List<Album> {
return makeAlbumsCursor(context, null, null)
.mapList(true) {
Album.fromCursor(this)
}
}
fun getSongsForAlbum(context: Context, albumId: Long): ArrayList<Song> {
return SongLoader.getSongs(makeAlbumSongCursor(context, albumId))
}
fun getAlbum(context: Context, id: Long): Album {
return getAlbum(makeAlbumsCursor(context, "_id=?", arrayOf(id.toString())))
}
fun getAlbumsForArtist(context: Context, artistId: Long): List<Album> {
return makeAlbumForArtistCursor(context, artistId).mapList(true) {
Album.fromCursor(this, artistId)
}
for (album in albums) {
sortSongsByTrackNumber(album)
}
private fun makeAlbumForArtistCursor(context: Context, artistId: Long): Cursor? {
if (artistId == -1L) {
return null
}
return context.contentResolver.query(
MediaStore.Audio.Artists.Albums.getContentUri("external", artistId),
arrayOf(
if (VersionUtils.hasQ()) MediaStore.Audio.Artists.Albums.ALBUM_ID else BaseColumns._ID,
MediaStore.Audio.Artists.Albums.ALBUM,
MediaStore.Audio.Artists.Albums.ARTIST,
MediaStore.Audio.Artists.Albums.NUMBER_OF_SONGS,
MediaStore.Audio.Artists.Albums.FIRST_YEAR
),
null,
null,
MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
)
}
private fun getAlbum(cursor: Cursor?): Album {
return cursor?.use {
if (cursor.moveToFirst()) {
Album.fromCursor(cursor)
} else {
null
}
} ?: Album()
}
private fun getAlbums(cursor: Cursor?): ArrayList<Album> {
val albums = ArrayList<Album>()
if (cursor != null && cursor.moveToFirst()) {
do {
albums.add(getAlbumFromCursorImpl(cursor))
} while (cursor.moveToNext())
}
return albums
}
private fun getOrCreateAlbum(
albums: ArrayList<Album>,
albumId: Int
): Album {
for (album in albums) {
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) {
return album
}
}
val album = Album()
albums.add(album)
return album
private fun getAlbumFromCursorImpl(cursor: Cursor): Album {
return Album.fromCursor(cursor)
}
private fun sortSongsByTrackNumber(album: Album) {
album.songs?.sortWith(Comparator { o1, o2 -> o1.trackNumber.compareTo(o2.trackNumber) })
private fun makeAlbumsCursor(context: Context, selection: String?, paramArrayOfString: Array<String>?): Cursor? {
return context.contentResolver.query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
arrayOf("_id", "album", "artist", "artist_id", "numsongs", "minyear"),
selection,
paramArrayOfString,
SortOrder.AlbumSortOrder.ALBUM_A_Z
)
}
private fun getSongLoaderSortOrder(context: Context): String {
return PreferenceUtil.getInstance(context).albumSortOrder + ", " + PreferenceUtil.getInstance(context).albumSongSortOrder
private fun makeAlbumSongCursor(context: Context, albumID: Long): Cursor? {
val selection = "is_music=1 AND title != '' AND album_id=$albumID"
return context.contentResolver.query(
SONGS_URI,
baseProjection,
selection,
null,
SortOrder.SongSortOrder.SONG_A_Z
)
}
}
}

View file

@ -15,14 +15,16 @@
package code.name.monkey.retromusic.loaders
import android.content.Context
import android.provider.MediaStore.Audio.AudioColumns
import code.name.monkey.retromusic.model.Album
import android.database.Cursor
import android.provider.MediaStore
import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.extensions.mapList
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.model.Song
object ArtistLoader {
private fun getSongLoaderSortOrder(context: Context): String {
/*private fun getSongLoaderSortOrder(context: Context): String {
return PreferenceUtil.getInstance(context).artistSortOrder + ", " + PreferenceUtil.getInstance(context).artistAlbumSortOrder + ", " + PreferenceUtil.getInstance(context).albumSongSortOrder
}
@ -32,7 +34,7 @@ object ArtistLoader {
null, null,
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
return splitIntoArtists(null)
}
fun getArtists(context: Context, query: String): ArrayList<Artist> {
@ -42,7 +44,7 @@ object ArtistLoader {
arrayOf("%$query%"),
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
return splitIntoArtists(null)
}
fun splitIntoArtists(albums: ArrayList<Album>?): ArrayList<Artist> {
@ -57,9 +59,9 @@ object ArtistLoader {
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist {
for (artist in artists) {
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
*//*if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
return artist
}
}*//*
}
val album = Artist()
artists.add(album)
@ -73,6 +75,66 @@ object ArtistLoader {
arrayOf(artistId.toString()),
getSongLoaderSortOrder(context))
)
return Artist(AlbumLoader.splitIntoAlbums(songs))
return Artist(ArrayList())
}*/
fun getAllArtists(context: Context): ArrayList<Artist> {
return getArtists(makeArtistCursor(context, null, null))
}
}
fun getArtist(context: Context, artistId: Long): Artist {
return getArtist(makeArtistCursor(context, "_id=?", arrayOf(artistId.toString())))
}
private fun getArtist(cursor: Cursor?): Artist {
return cursor?.use {
if (cursor.moveToFirst()) {
Artist.fromCursor(cursor)
} else {
null
}
} ?: Artist()
}
private fun getArtists(cursor: Cursor?): ArrayList<Artist> {
val artists = ArrayList<Artist>()
if (cursor != null && cursor.moveToFirst()) {
do {
artists.add(getArtistFromCursor(cursor))
} while (cursor.moveToNext())
}
return artists
}
private fun getArtistFromCursor(cursor: Cursor): Artist {
return Artist.fromCursor(cursor)
}
private fun makeArtistCursor(context: Context, selection: String?, paramArrayOfString: Array<String>?): Cursor? {
return context.contentResolver.query(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
arrayOf("_id", "artist", "number_of_albums", "number_of_tracks"),
selection,
paramArrayOfString,
SortOrder.ArtistSortOrder.ARTIST_A_Z
)
}
fun getSongsForArtist(context: Context, artistId: Long): List<Any> {
return makeArtistSongCursor(context, artistId)
.mapList(true) { Song.fromCursor(this, artistId = artistId) }
}
private fun makeArtistSongCursor(context: Context, artistId: Long): Cursor? {
val artistSongSortOrder = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val selection = "is_music=1 AND title != '' AND artist_id=$artistId"
return context.contentResolver.query(
uri,
baseProjection,
selection,
null,
artistSongSortOrder
)
}
}

View file

@ -43,10 +43,10 @@ object LastAddedSongsLoader {
}
fun getLastAddedAlbums(context: Context): ArrayList<Album> {
return AlbumLoader.splitIntoAlbums(getLastAddedSongs(context))
return ArrayList()
}
fun getLastAddedArtists(context: Context): ArrayList<Artist> {
return ArtistLoader.splitIntoArtists(getLastAddedAlbums(context))
return ArrayList()
}
}

View file

@ -16,6 +16,8 @@ package code.name.monkey.retromusic.loaders
import android.content.Context
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Genre
import java.util.Locale
@ -29,13 +31,13 @@ object SearchLoader {
results.addAll(songs)
}
val artists = ArtistLoader.getArtists(context, searchString)
val artists = emptyArray<Artist>()//ArtistLoader.getArtists(context, searchString)
if (artists.isNotEmpty()) {
results.add(context.resources.getString(R.string.artists))
results.addAll(artists)
}
val albums = AlbumLoader.getAlbums(context, searchString)
val albums = emptyArray<Album>()//AlbumLoader.getAlbums(context, searchString)
if (albums.isNotEmpty()) {
results.add(context.resources.getString(R.string.albums))
results.addAll(albums)

View file

@ -83,7 +83,7 @@ object SongLoader {
private fun getSongFromCursorImpl(
cursor: Cursor
): Song {
val id = cursor.getInt(0)
val id = cursor.getLong(0)
val title = cursor.getString(1)
val trackNumber = cursor.getInt(2)
val year = cursor.getInt(3)
@ -92,7 +92,7 @@ object SongLoader {
val dateModified = cursor.getLong(6)
val albumId = cursor.getInt(7)
val albumName = cursor.getString(8)
val artistId = cursor.getInt(9)
val artistId = cursor.getLong(9)
val artistName = cursor.getString(10)
val composer = cursor.getString(11)

View file

@ -139,10 +139,10 @@ object TopAndRecentlyPlayedTracksLoader {
context: Context
): ArrayList<Album> {
arrayListOf<Album>()
return AlbumLoader.splitIntoAlbums(getTopTracks(context))
return ArrayList()//AlbumLoader.splitIntoAlbums(getTopTracks(context))
}
fun getTopArtists(context: Context): ArrayList<Artist> {
return ArtistLoader.splitIntoArtists(getTopAlbums(context))
return ArrayList()//ArtistLoader.splitIntoArtists(getTopAlbums(context))
}
}

View file

@ -1,50 +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.misc
import android.content.Context
import android.text.TextUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.loaders.ArtistLoader
import code.name.monkey.retromusic.loaders.SongLoader
import java.util.*
internal class AsyncSearchResultLoader(context: Context, private val query: String) : WrappedAsyncTaskLoader<List<Any>>(context) {
override fun loadInBackground(): List<Any>? {
val results = ArrayList<Any>()
if (!TextUtils.isEmpty(query)) {
val songs = SongLoader.getSongs(context, query.trim { it <= ' ' })
if (!songs.isEmpty()) {
results.add(context.resources.getString(R.string.songs))
results.addAll(songs)
}
val artists = ArtistLoader.getArtists(context, query.trim { it <= ' ' })
if (!artists.isEmpty()) {
results.add(context.resources.getString(R.string.artists))
results.addAll(artists)
}
val albums = AlbumLoader.getAlbums(context, query.trim { it <= ' ' })
if (!albums.isEmpty()) {
results.add(context.resources.getString(R.string.albums))
results.addAll(albums)
}
}
return results
}
}

View file

@ -14,41 +14,69 @@
package code.name.monkey.retromusic.model
import java.util.ArrayList
import android.database.Cursor
import android.provider.MediaStore.Audio.Albums.ALBUM
import android.provider.MediaStore.Audio.Albums.ARTIST
import android.provider.MediaStore.Audio.Albums.FIRST_YEAR
import android.provider.MediaStore.Audio.Albums.NUMBER_OF_SONGS
import android.provider.MediaStore.Audio.Albums._ID
import android.provider.MediaStore.Audio.Artists.Albums.ALBUM_ID
import code.name.monkey.appthemehelper.util.VersionUtils
class Album {
val songs: ArrayList<Song>?
data class Album(
var id: Long = 0,
var title: String = "",
var artist: String = "",
var artistId: Long = 0,
var songCount: Int = 0,
var year: Int = 0
) {
val id: Int
get() = safeGetFirstSong().albumId
val title: String?
get() = safeGetFirstSong().albumName
val artistId: Int
get() = safeGetFirstSong().artistId
val artistName: String?
get() = safeGetFirstSong().artistName
val year: Int
get() = safeGetFirstSong().year
val dateModified: Long
get() = safeGetFirstSong().dateModified
val songCount: Int
get() = songs!!.size
constructor(songs: ArrayList<Song>) {
this.songs = songs
}
constructor() {
this.songs = ArrayList()
}
fun safeGetFirstSong(): Song {
return if (songs!!.isEmpty()) Song.emptySong else songs[0]
companion object {
fun fromCursor(cursor: Cursor, artistId: Long = -1): Album {
return Album(
id = cursor.value(if (VersionUtils.hasQ()) ALBUM_ID else _ID),
title = cursor.valueOrEmpty(ALBUM),
artist = cursor.valueOrEmpty(ARTIST),
artistId = artistId,
songCount = cursor.value(NUMBER_OF_SONGS),
year = cursor.value(FIRST_YEAR)
)
}
}
}
fun Cursor.valueOrEmpty(name: String): String = valueOrDefault(name, "")
inline fun <reified T> Cursor.value(name: String): T {
val index = getColumnIndexOrThrow(name)
return when (T::class) {
Short::class -> getShort(index) as T
Int::class -> getInt(index) as T
Long::class -> getLong(index) as T
Boolean::class -> (getInt(index) == 1) as T
String::class -> getString(index) as T
Float::class -> getFloat(index) as T
Double::class -> getDouble(index) as T
ByteArray::class -> getBlob(index) as T
else -> throw IllegalStateException("What do I do with ${T::class.java.simpleName}?")
}
}
inline fun <reified T> Cursor.valueOrDefault(name: String, defaultValue: T): T {
val index = getColumnIndex(name)
if (index == -1) {
return defaultValue
}
return when (T::class) {
Short::class -> getShort(index) as? T ?: defaultValue
Int::class -> getInt(index) as? T ?: defaultValue
Long::class -> getLong(index) as? T ?: defaultValue
Boolean::class -> (getInt(index) == 1) as T
String::class -> getString(index) as? T ?: defaultValue
Float::class -> getFloat(index) as? T ?: defaultValue
Double::class -> getDouble(index) as? T ?: defaultValue
ByteArray::class -> getBlob(index) as? T ?: defaultValue
else -> throw IllegalStateException("What do I do with ${T::class.java.simpleName}?")
}
}

View file

@ -14,18 +14,27 @@
package code.name.monkey.retromusic.model
import code.name.monkey.retromusic.util.MusicUtil
import java.util.ArrayList
import android.database.Cursor
import android.provider.MediaStore.Audio.Artists.ARTIST
import android.provider.MediaStore.Audio.Artists.NUMBER_OF_ALBUMS
import android.provider.MediaStore.Audio.Artists.NUMBER_OF_TRACKS
import android.provider.MediaStore.Audio.Artists._ID
class Artist {
val albums: ArrayList<Album>?
class Artist(
var id: Long = 0,
var name: String = "",
var songCount: Int = 0,
var albumCount: Int = 0
) {
/*val albums: ArrayList<Album>?
val id: Int
get() = safeGetFirstAlbum().artistId
val name: String
get() {
val name = safeGetFirstAlbum().artistName
val name = safeGetFirstAlbum().artist
return if (MusicUtil.isArtistNameUnknown(name)) {
UNKNOWN_ARTIST_DISPLAY_NAME
} else name!!
@ -47,7 +56,7 @@ class Artist {
get() {
val songs = ArrayList<Song>()
for (album in albums!!) {
songs.addAll(album.songs!!)
//songs.addAll(album.songs!!)
}
return songs
}
@ -63,8 +72,18 @@ class Artist {
fun safeGetFirstAlbum(): Album {
return if (albums!!.isEmpty()) Album() else albums[0]
}
*/
companion object {
fun fromCursor(cursor: Cursor): Artist {
return Artist(
id = cursor.value(_ID),
name = cursor.value(ARTIST),
songCount = cursor.value(NUMBER_OF_TRACKS),
albumCount = cursor.value(NUMBER_OF_ALBUMS)
)
}
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
}
}

View file

@ -13,12 +13,14 @@
*/
package code.name.monkey.retromusic.model
import android.database.Cursor
import android.os.Parcelable
import android.provider.MediaStore.Audio.Media
import kotlinx.android.parcel.Parcelize
@Parcelize
open class Song(
val id: Int,
val id: Long,
val title: String,
val trackNumber: Int,
val year: Int,
@ -27,7 +29,7 @@ open class Song(
val dateModified: Long,
val albumId: Int,
val albumName: String,
val artistId: Int,
val artistId: Long,
val artistName: String,
val composer: String?
) : Parcelable {
@ -49,5 +51,22 @@ open class Song(
"",
""
)
fun fromCursor(cursor: Cursor, artistId: Long): Any {
return Song(
id = cursor.value(Media._ID),
albumId = cursor.value(Media.ALBUM_ID),
artistId = cursor.value(Media.ARTIST_ID),
albumName = cursor.valueOrEmpty(Media.ALBUM),
artistName = cursor.valueOrEmpty(Media.ARTIST),
composer = cursor.valueOrEmpty(Media.COMPOSER),
data = cursor.valueOrEmpty(Media.DATA),
dateModified = cursor.value(Media.DATE_ADDED),
duration = cursor.value(Media.DURATION),
title = cursor.valueOrEmpty(Media.TITLE),
trackNumber = cursor.value(Media.TRACK),
year = cursor.value(Media.YEAR)
)
}
}
}

View file

@ -14,9 +14,12 @@
package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.Result.Success
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository
@ -36,6 +39,8 @@ interface AlbumDetailsView {
fun album(album: Album)
fun songs(songs: ArrayList<Song>)
fun complete()
fun loadArtistImage(artist: Artist)
@ -48,9 +53,12 @@ interface AlbumDetailsView {
}
interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
fun loadAlbum(albumId: Int)
fun loadAlbum(albumId: Long)
fun albumSong(albumId: Long)
fun loadMore(artistId: Long)
fun loadMore(artistId: Int)
fun aboutAlbum(artist: String, album: String)
class AlbumDetailsPresenterImpl @Inject constructor(
@ -60,7 +68,7 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private val job = Job()
private lateinit var album: Album
override fun loadMore(artistId: Int) {
override fun loadMore(artistId: Long) {
launch {
when (val result = repository.artistById(artistId)) {
is Success -> withContext(Dispatchers.Main) { showArtistImage(result.data) }
@ -81,12 +89,12 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private fun showArtistImage(artist: Artist) {
view?.loadArtistImage(artist)
artist.albums?.filter { it.id != album.id }?.let {
/* artist.albums?.filter { it.id != album.id }?.let {
if (it.isNotEmpty()) view?.moreAlbums(ArrayList(it))
}
}*/
}
override fun loadAlbum(albumId: Int) {
override fun loadAlbum(albumId: Long) {
launch {
when (val result = repository.albumById(albumId)) {
is Success -> withContext(Dispatchers.Main) {
@ -98,6 +106,15 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
}
}
override fun albumSong(albumId: Long) {
launch {
val songs = AlbumLoader.getSongsForAlbum(App.getContext(), albumId)
withContext(Dispatchers.Main) {
view.songs(songs)
}
}
}
override fun detachView() {
super.detachView()
job.cancel()

View file

@ -25,7 +25,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.ArrayList
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@ -33,35 +32,37 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 12/08/17.
*/
interface AlbumsView : BaseView {
fun albums(albums: ArrayList<Album>)
fun albums(albums: List<Album>)
}
interface AlbumsPresenter : Presenter<AlbumsView> {
fun loadAlbums()
fun loadAlbums()
class AlbumsPresenterImpl @Inject constructor(
class AlbumsPresenterImpl @Inject constructor(
private val repository: Repository
) : PresenterImpl<AlbumsView>(), AlbumsPresenter, CoroutineScope {
private val job = Job()
) : PresenterImpl<AlbumsView>(), AlbumsPresenter, CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
private val job = Job()
override fun detachView() {
super.detachView()
job.cancel()
}
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun loadAlbums() {
launch {
when (val result = repository.allAlbums()) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.albums(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
}
override fun detachView() {
super.detachView()
job.cancel()
}
override fun loadAlbums() {
launch {
when (val result = repository.allAlbums()) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.albums(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
}
}

View file

@ -14,8 +14,12 @@
package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
@ -35,14 +39,24 @@ import kotlin.coroutines.CoroutineContext
*/
interface ArtistDetailsView : BaseView {
fun songs(songs: ArrayList<Song>)
fun albums(albums: List<Album>)
fun artist(artist: Artist)
fun artistInfo(lastFmArtist: LastFmArtist?)
fun complete()
}
interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
fun loadArtist(artistId: Int)
fun loadArtist(artistId: Long)
fun loadArtistSongs(artistId: Long)
fun loadArtistAlbums(artistId: Long)
fun loadBiography(
name: String,
@ -72,7 +86,7 @@ interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
}
}
override fun loadArtist(artistId: Int) {
override fun loadArtist(artistId: Long) {
launch {
when (val result = repository.artistById(artistId)) {
is Result.Success -> withContext(Dispatchers.Main) {
@ -86,6 +100,24 @@ interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
}
}
override fun loadArtistSongs(artistId: Long) {
launch {
val songs = AlbumLoader.getSongsForAlbum(App.getContext(), artistId)
withContext(Dispatchers.Main) {
view.songs(songs)
}
}
}
override fun loadArtistAlbums(artistId: Long) {
launch {
val albums = AlbumLoader.getAlbumsForArtist(App.getContext(), artistId)
withContext(Dispatchers.Main) {
view.albums(albums)
}
}
}
override fun detachView() {
super.detachView()
job.cancel()

View file

@ -45,7 +45,7 @@ import javax.inject.Inject
class RepositoryImpl @Inject constructor(private val context: Context) : Repository {
override suspend fun allAlbums(): Result<ArrayList<Album>> {
override suspend fun allAlbums(): Result<List<Album>> {
return try {
val albums = AlbumLoader.getAllAlbums(context)
if (albums.isNotEmpty()) {
@ -58,14 +58,10 @@ class RepositoryImpl @Inject constructor(private val context: Context) : Reposit
}
}
override suspend fun albumById(albumId: Int): Result<Album> {
override suspend fun albumById(albumId: Long): Result<Album> {
return try {
val album = AlbumLoader.getAlbum(context, albumId)
if (album != null) {
Success(album)
} else {
Error(Throwable("No album"))
}
Success(album)
} catch (e: Exception) {
Error(e)
}
@ -289,7 +285,7 @@ class RepositoryImpl @Inject constructor(private val context: Context) : Reposit
errorMessage = "Error"
)
override suspend fun artistById(artistId: Int): Result<Artist> {
override suspend fun artistById(artistId: Long): Result<Artist> {
return try {
val artist = ArtistLoader.getArtist(context, artistId)
return Success(artist)

View file

@ -30,9 +30,9 @@ import code.name.monkey.retromusic.rest.model.LastFmArtist
interface Repository {
suspend fun allAlbums(): Result<ArrayList<Album>>
suspend fun allAlbums(): Result<List<Album>>
suspend fun albumById(albumId: Int): Result<Album>
suspend fun albumById(albumId: Long): Result<Album>
suspend fun allSongs(): Result<ArrayList<Song>>
@ -62,5 +62,5 @@ interface Repository {
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum>
suspend fun artistById(artistId: Int): Result<Artist>
suspend fun artistById(artistId: Long): Result<Artist>
}

View file

@ -642,7 +642,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) {

View file

@ -1,370 +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.service;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.media.MediaDescription;
import android.media.browse.MediaBrowser;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.loaders.AlbumLoader;
import code.name.monkey.retromusic.loaders.ArtistLoader;
import code.name.monkey.retromusic.loaders.PlaylistLoader;
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.model.Album;
import code.name.monkey.retromusic.model.Artist;
import code.name.monkey.retromusic.model.Playlist;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.util.MusicUtil;
import code.name.monkey.retromusic.util.RetroUtil;
/**
* @author Hemanth S (h4h13).
*/
@TargetApi(21)
public class WearBrowserService extends MediaBrowserService {
public static final String MEDIA_ID_ROOT = "__ROOT__";
public static final int TYPE_ARTIST = 0;
public static final int TYPE_ALBUM = 1;
public static final int TYPE_SONG = 2;
public static final int TYPE_PLAYLIST = 3;
public static final int TYPE_ARTIST_SONG_ALBUMS = 4;
public static final int TYPE_ALBUM_SONGS = 5;
public static final int TYPE_ARTIST_ALL_SONGS = 6;
public static final int TYPE_PLAYLIST_ALL_SONGS = 7;
public static WearBrowserService sInstance;
private MediaSession mSession;
private Context mContext;
private boolean mServiceStarted;
public static WearBrowserService getInstance() {
return sInstance;
}
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
mContext = this;
mSession = new MediaSession(this, "WearBrowserService");
setSessionToken(mSession.getSessionToken());
mSession.setCallback(new MediaSessionCallback());
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
@Override
public int onStartCommand(Intent startIntent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
mServiceStarted = false;
mSession.release();
}
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String s, int i, @Nullable Bundle bundle) {
return new BrowserRoot(MEDIA_ID_ROOT, null);
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowser.MediaItem>> result) {
result.detach();
loadChildren(parentId, result);
}
private void setSessionActive() {
if (!mServiceStarted) {
startService(new Intent(getApplicationContext(), WearBrowserService.class));
mServiceStarted = true;
}
if (!mSession.isActive()) {
mSession.setActive(true);
}
}
private void setSessionInactive() {
if (mServiceStarted) {
stopSelf();
mServiceStarted = false;
}
if (mSession.isActive()) {
mSession.setActive(false);
}
}
private void fillMediaItems(List<MediaBrowser.MediaItem> mediaItems,
String mediaId,
String title,
String subTitle,
Uri icon,
int playableOrBrowsable) {
mediaItems.add(new MediaBrowser.MediaItem(
new MediaDescription.Builder()
.setMediaId(mediaId)
.setTitle(title)
.setIconUri(icon)
.setSubtitle(subTitle)
.build(), playableOrBrowsable
));
}
private void addMediaRoots(List<MediaBrowser.MediaItem> mMediaRoot) {
mMediaRoot.add(new MediaBrowser.MediaItem(
new MediaDescription.Builder()
.setMediaId(Integer.toString(TYPE_ARTIST))
.setTitle(getString(R.string.artists))
.setIconBitmap(RetroUtil.createBitmap(ContextCompat.getDrawable(getApplicationContext(), R.drawable.default_artist_art), 1f))
.setSubtitle(getString(R.string.artists))
.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
));
mMediaRoot.add(new MediaBrowser.MediaItem(
new MediaDescription.Builder()
.setMediaId(Integer.toString(TYPE_ALBUM))
.setTitle(getString(R.string.albums))
.setIconBitmap(RetroUtil.createBitmap(ContextCompat.getDrawable(getApplicationContext(), R.drawable.default_album_art), 1f))
.setSubtitle(getString(R.string.albums))
.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
));
mMediaRoot.add(new MediaBrowser.MediaItem(
new MediaDescription.Builder()
.setMediaId(Integer.toString(TYPE_SONG))
.setTitle(getString(R.string.songs))
.setIconBitmap(RetroUtil.createBitmap(ContextCompat.getDrawable(getApplicationContext(), R.drawable.default_album_art), 1f))
.setSubtitle(getString(R.string.songs))
.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
));
mMediaRoot.add(new MediaBrowser.MediaItem(
new MediaDescription.Builder()
.setMediaId(Integer.toString(TYPE_PLAYLIST))
.setTitle(getString(R.string.playlists))
.setIconUri(Uri.parse("android.resource://code.name.monkey.retromusic/drawable/ic_queue_music_white_24dp"))
.setSubtitle(getString(R.string.playlists))
.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
));
}
private void loadChildren(final String parentId, final Result<List<MediaBrowser.MediaItem>> result) {
final List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(final Void... unused) {
if (parentId.equals(MEDIA_ID_ROOT)) {
addMediaRoots(mediaItems);
} else {
switch (Integer.parseInt(Character.toString(parentId.charAt(0)))) {
case TYPE_ARTIST:
List<Artist> artistList = ArtistLoader.INSTANCE.getAllArtists(mContext) ;
for (Artist artist : artistList) {
String albumNmber = String.format("%d %s", artist.getAlbums().size(), artist.getAlbums().size() > 1 ? "Albums" : "Album");
String songCount = String.format("%d %s", artist.getSongs().size(), artist.getSongs().size() > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_ARTIST_SONG_ALBUMS) + Long.toString(artist.getId()),
artist.getName(),
albumNmber + "" + songCount,
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_artist_art"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
}
break;
case TYPE_ARTIST_SONG_ALBUMS:
fillMediaItems(mediaItems,
Integer.toString(TYPE_ARTIST_ALL_SONGS) + Long.parseLong(parentId.substring(1)),
"All songs",
"All songs by artist",
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_artist_art"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
List<Album> artistAlbums = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).getAlbums(); //ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
for (Album album : artistAlbums) {
String songCount = String.format("%d %s", album.getSongs().size(), album.getSongs().size() > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.getId()),
album.getTitle(),
songCount,
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_artist_art"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
}
break;
case TYPE_ALBUM:
List<Album> albumList = AlbumLoader.INSTANCE.getAllAlbums(mContext);
for (Album album : albumList) {
fillMediaItems(mediaItems,
Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.getId()),
album.getTitle(),
album.getArtistName(),
MusicUtil.getMediaStoreAlbumCoverUri(album.getId()),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
}
break;
case TYPE_SONG:
List<Song> songList = SongLoader.INSTANCE.getAllSongs(mContext);
for (Song song : songList) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_ALBUM_SONGS:
List<Song> albumSongList = AlbumLoader.INSTANCE.getAlbum(mContext, Integer.parseInt(parentId.substring(1))).getSongs();
for (Song song : albumSongList) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_ARTIST_ALL_SONGS:
List<Song> artistSongs = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).getSongs();
for (Song song : artistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_PLAYLIST:
List<Playlist> playlistList = PlaylistLoader.INSTANCE.getAllPlaylists(mContext);
for (Playlist playlist : playlistList) {
int size = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, playlist).size();
String songCount = String.format("%d %s", size, size > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_PLAYLIST_ALL_SONGS) + Long.toString(playlist.id),
playlist.name,
songCount,
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/ic_queue_music_white_24dp"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
}
break;
case TYPE_PLAYLIST_ALL_SONGS:
List<Song> playlistSongs = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, Integer.parseInt(parentId.substring(1)));
for (Song song : playlistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
}
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
result.sendResult(mediaItems);
}
}.execute();
}
private final class MediaSessionCallback extends MediaSession.Callback {
@Override
public void onPlay() {
setSessionActive();
}
@Override
public void onSeekTo(long position) {
}
@Override
public void onPlayFromMediaId(final String mediaId, Bundle extras) {
long songId = Long.parseLong(mediaId);
setSessionActive();
ArrayList<Song> songs = new ArrayList<>();
songs.add(SongLoader.INSTANCE.getSong(mContext, Integer.parseInt(mediaId)));
MusicPlayerRemote.INSTANCE.openQueue(songs, 0, true);
}
@Override
public void onPause() {
}
@Override
public void onStop() {
setSessionInactive();
}
@Override
public void onSkipToNext() {
}
@Override
public void onSkipToPrevious() {
}
@Override
public void onFastForward() {
}
@Override
public void onRewind() {
}
@Override
public void onCustomAction(@NonNull String action, Bundle extras) {
}
}
}

View file

@ -262,7 +262,7 @@ public class MusicUtil {
}
@NonNull
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
public static Uri getMediaStoreAlbumCoverUri(long albumId) {
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
return ContentUris.withAppendedId(sArtworkUri, albumId);
}
@ -322,7 +322,7 @@ public class MusicUtil {
return songCount + " " + songString;
}
public static Uri getSongFileUri(int songId) {
public static Uri getSongFileUri(long songId) {
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
}

View file

@ -66,7 +66,7 @@ public class NavigationUtil {
}
public static void goToAlbumOptions(@NonNull Activity activity,
int albumId,
long albumId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
@ -80,7 +80,7 @@ public class NavigationUtil {
}
public static void goToArtistOptions(@NotNull Activity activity,
int artistId,
long artistId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, ArtistDetailActivity.class);

View file

@ -130,7 +130,7 @@ public class PlaylistsUtil {
}
static boolean doPlaylistContains(@NonNull final Context context, final long playlistId,
final int songId) {
final long songId) {
if (playlistId != -1) {
try {
Cursor c = context.getContentResolver().query(

View file

@ -42,4 +42,8 @@ object VersionUtils {
fun hasOreo(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
}
fun hasQ(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}
}