Compare commits

...
Sign in to create a new pull request.

7 commits

Author SHA1 Message Date
h4h13
3a0e130e06 Code refactor 2020-02-12 23:44:19 +05:30
h4h13
d8dc39d293 Fix full screen layout issue 2020-02-06 21:52:47 +05:30
h4h13
102d18cd6a Refactor Arraylist to List 2020-02-06 14:57:10 +05:30
h4h13
393bd59a1c Fix album style & search 2020-02-06 12:22:34 +05:30
h4h13
eee663f717 Improved album and artist grid style change 2020-02-06 11:09:10 +05:30
h4h13
6b959ec24a Major refactor about artist and album 2020-02-06 10:47:43 +05:30
h4h13
b922549dee Refactor 2020-02-05 17:14:22 +05:30
101 changed files with 1428 additions and 1599 deletions

View file

@ -22,8 +22,8 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic" applicationId "code.name.monkey.retromusic"
versionCode 405 versionCode 408
versionName '3.4.900' versionName '3.5.000'
multiDexEnabled true multiDexEnabled true
@ -129,8 +129,8 @@ dependencies {
implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.fragment:fragment:1.2.0' implementation 'androidx.fragment:fragment:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.0-alpha04' implementation 'com.google.android.material:material:1.2.0-alpha04'

View file

@ -1 +1 @@
<html> <head> <style type="text/css"> * { word-wrap: break-word; } {style-placeholder} a { color: {link-color}; } a:active { color: {link-color-active}; } ol { list-style-position: inside; padding-left: 0; padding-right: 0; } li { padding-top: 8px; } </style> </head> <body> <h4>v3.4.900</h4> <ul> <li>Added playlist search</li> <li>Added Drive mode</li> <li>Added Album and Artist layout change option in library</li> <li>Added Show more album and artist information in details</li> <li>Added Pixel style scroller bar</li> <li>Added current now playing share</li> <li>Fix font issues and colors in some places</li> <li>Improved Full now playing theme</li> </ul> <h4>v3.4.850</h4> <ul> <li>Added new theme called circle</li> <li>Added tiny color card style for home artists</li> <li>Added extra track info details to now playing themes</li> <li>Added scroll animation</li> <li>Added smooth transition animations 🤔</li> <li>Added current playing tab options for Bottom Navigation View</li> <li>Added search in genre</li> <li>Improved selecting feedback effect(ripple with corners)</li> <li>Fix bugs & crashes</li> <li>Fix crashing on lyrics</li> <li>Fix genre details last song is under mini player</li> <li>Fix colors mistakes and font sizes</li> <li>Fix slider jumping while scrolling in now playing themes</li> </ul> <h4>v3.4.800</h4> <ul> <li>Improved dark theme colors and Follow system theme</li> <li>Rounded rectangle ripple for BottomNavigationView</li> <li>Follow sleep timer dialog checkbox color as accent</li> <li>Added song list selection for Album and Artist details</li> <li>Fixed Toolbar popup text color when selecting songs</li> </ul> <h4>v3.4.700</h4> <ul> <li>Added splash screen(for app loading time)</li> <li>Updated dark theme colors</li> <li>Added circular progress view</li> <li>Hiding year if not showing</li> </ul> <h4>v3.4.600</h4> <ul> <li>Fix notification layout height</li> <li>Fix folder list last item not showing</li> <li>Added auto hide/ show controls according to first and last item</li> </ul> <h4>v3.4.500</h4> <ul> <li>Added peak theme</li> <li>Added app rating dialog</li> <li>Fix song name scrolling in now playing themes if it's long</li> <li>Fix playing queue last item hiding FAB</li> <li>Added desaturated color option for dark mode</li> <li>Fix slow search loading</li> <li>Fix last added slow loading</li> <li>Fix home banner toolbar corner</li> <li>Fix home crashing when switching between two tabs</li> <li>Fix remaining time in playing queue</li> <li>Fix font not applied for some components</li> <li>Fix crashing on album details sorting</li> <li>Fixed lot of internal bugs</li> <li>Fix dialog expand</li> <li>Fix list card color</li> <li>Removed SlidingUpPanel to replace with BottomSheet</li> <li>Removed color theme as per material design guidelines</li> <li>Removed classic theme(We're bringing back)</li> <li>Replace line switch to Material Switch in settings</li> <li>Performance improved</li> <li>Updated internal libraries</li> <li>Updated translation</li> <li>Limiting the use of Theme engine for making use of system colors</li> <li>Change home icon from the user icon</li> <li>Corrected all toolbar with elevation when scrolling</li> </ul> <p>If you see entire app white or dark or black select same theme in settings to fix </p> <p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a> </p> <p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again. </p> </body> <html> <head> <style type="text/css"> * { word-wrap: break-word; } {style-placeholder} a { color: {link-color}; } a:active { color: {link-color-active}; } ol { list-style-position: inside; padding-left: 0; padding-right: 0; } li { padding-top: 8px; } </style> </head> <body> <h4>v.3.5.000</h4> <ul> <li>Major code refactor for Album and Artist loading</li> </ul> <h4>v3.4.900</h4> <ul> <li>Added playlist search</li> <li>Added Drive mode</li> <li>Added Album and Artist layout change option in library</li> <li>Added Show more album and artist information in details</li> <li>Added Pixel style scroller bar</li> <li>Added current now playing share</li> <li>Fix font issues and colors in some places</li> <li>Improved Full now playing theme</li> </ul> <h4>v3.4.850</h4> <ul> <li>Added new theme called circle</li> <li>Added tiny color card style for home artists</li> <li>Added extra track info details to now playing themes</li> <li>Added scroll animation</li> <li>Added smooth transition animations 🤔</li> <li>Added current playing tab options for Bottom Navigation View</li> <li>Added search in genre</li> <li>Improved selecting feedback effect(ripple with corners)</li> <li>Fix bugs & crashes</li> <li>Fix crashing on lyrics</li> <li>Fix genre details last song is under mini player</li> <li>Fix colors mistakes and font sizes</li> <li>Fix slider jumping while scrolling in now playing themes</li> </ul> <h4>v3.4.800</h4> <ul> <li>Improved dark theme colors and Follow system theme</li> <li>Rounded rectangle ripple for BottomNavigationView</li> <li>Follow sleep timer dialog checkbox color as accent</li> <li>Added song list selection for Album and Artist details</li> <li>Fixed Toolbar popup text color when selecting songs</li> </ul> <h4>v3.4.700</h4> <ul> <li>Added splash screen(for app loading time)</li> <li>Updated dark theme colors</li> <li>Added circular progress view</li> <li>Hiding year if not showing</li> </ul> <h4>v3.4.600</h4> <ul> <li>Fix notification layout height</li> <li>Fix folder list last item not showing</li> <li>Added auto hide/ show controls according to first and last item</li> </ul> <h4>v3.4.500</h4> <ul> <li>Added peak theme</li> <li>Added app rating dialog</li> <li>Fix song name scrolling in now playing themes if it's long</li> <li>Fix playing queue last item hiding FAB</li> <li>Added desaturated color option for dark mode</li> <li>Fix slow search loading</li> <li>Fix last added slow loading</li> <li>Fix home banner toolbar corner</li> <li>Fix home crashing when switching between two tabs</li> <li>Fix remaining time in playing queue</li> <li>Fix font not applied for some components</li> <li>Fix crashing on album details sorting</li> <li>Fixed lot of internal bugs</li> <li>Fix dialog expand</li> <li>Fix list card color</li> <li>Removed SlidingUpPanel to replace with BottomSheet</li> <li>Removed color theme as per material design guidelines</li> <li>Removed classic theme(We're bringing back)</li> <li>Replace line switch to Material Switch in settings</li> <li>Performance improved</li> <li>Updated internal libraries</li> <li>Updated translation</li> <li>Limiting the use of Theme engine for making use of system colors</li> <li>Change home icon from the user icon</li> <li>Corrected all toolbar with elevation when scrolling</li> </ul> <p>If you see entire app white or dark or black select same theme in settings to fix </p> <p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a> </p> <p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again. </p> </body>

View file

@ -31,7 +31,7 @@ object Constants {
const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md" const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
const val PINTEREST = "https://in.pinterest.com/retromusicapp/" const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''" const val baseSelection = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
val baseProjection = arrayOf(BaseColumns._ID, // 0 val baseProjection = arrayOf(BaseColumns._ID, // 0
MediaStore.Audio.AudioColumns.TITLE, // 1 MediaStore.Audio.AudioColumns.TITLE, // 1

View file

@ -8,7 +8,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.SubMenu import android.view.SubMenu
import android.view.View import android.view.View
import android.widget.ImageView
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -27,14 +26,15 @@ import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.ripAlpha import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget 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.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist 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.AlbumDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView
import code.name.monkey.retromusic.rest.model.LastFmAlbum import code.name.monkey.retromusic.rest.model.LastFmAlbum
@ -48,6 +48,7 @@ import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_album.albumCoverContainer import kotlinx.android.synthetic.main.activity_album.albumCoverContainer
import kotlinx.android.synthetic.main.activity_album.albumText import kotlinx.android.synthetic.main.activity_album.albumText
import kotlinx.android.synthetic.main.activity_album.albumTitle import kotlinx.android.synthetic.main.activity_album.albumTitle
import kotlinx.android.synthetic.main.activity_album.artistImage
import kotlinx.android.synthetic.main.activity_album.image import kotlinx.android.synthetic.main.activity_album.image
import kotlinx.android.synthetic.main.activity_album.toolbar import kotlinx.android.synthetic.main.activity_album.toolbar
import kotlinx.android.synthetic.main.activity_album_content.aboutAlbumText import kotlinx.android.synthetic.main.activity_album_content.aboutAlbumText
@ -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.scrobblesLabel
import kotlinx.android.synthetic.main.activity_album_content.shuffleAction import kotlinx.android.synthetic.main.activity_album_content.shuffleAction
import kotlinx.android.synthetic.main.activity_album_content.songTitle import kotlinx.android.synthetic.main.activity_album_content.songTitle
import java.util.ArrayList
import javax.inject.Inject import javax.inject.Inject
import android.util.Pair as UtilPair import android.util.Pair as UtilPair
@ -88,8 +88,9 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
private lateinit var simpleSongAdapter: SimpleSongAdapter private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album private lateinit var album: Album
private lateinit var artistImage: ImageView private lateinit var songs: List<Song>
private var cab: MaterialCab? = null private var cab: MaterialCab? = null
private val savedSortOrder: String private val savedSortOrder: String
get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder
@ -106,7 +107,6 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
slide.excludeTarget(R.id.status_bar, true) slide.excludeTarget(R.id.status_bar, true)
slide.excludeTarget(android.R.id.statusBarBackground, true) slide.excludeTarget(android.R.id.statusBarBackground, true)
slide.excludeTarget(android.R.id.navigationBarBackground, true) slide.excludeTarget(android.R.id.navigationBarBackground, true)
window.enterTransition = slide window.enterTransition = slide
} }
@ -124,7 +124,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
albumDetailsPresenter.attachView(this) albumDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) { if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { intent.extras?.getLong(EXTRA_ALBUM_ID)?.let {
albumDetailsPresenter.loadAlbum(it) albumDetailsPresenter.loadAlbum(it)
albumCoverContainer?.transitionName = "${getString(R.string.transition_album_art)}_$it" albumCoverContainer?.transitionName = "${getString(R.string.transition_album_art)}_$it"
} }
@ -135,12 +135,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
windowEnterTransition() windowEnterTransition()
ActivityCompat.postponeEnterTransition(this) ActivityCompat.postponeEnterTransition(this)
artistImage = findViewById(R.id.artistImage)
setupRecyclerView() setupRecyclerView()
artistImage.setOnClickListener { artistImage.setOnClickListener {
println("Click Artist $album")
val artistPairs = ActivityOptions.makeSceneTransitionAnimation( val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
this, this,
UtilPair.create( UtilPair.create(
@ -151,10 +149,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs) NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
} }
playAction.apply { playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) } setOnClickListener { MusicPlayerRemote.openQueue(songs, 0, true) }
} }
shuffleAction.apply { shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) } setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(songs, true) }
} }
aboutAlbumText.setOnClickListener { aboutAlbumText.setOnClickListener {
@ -187,39 +185,30 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
override fun album(album: Album) { override fun album(album: Album) {
complete() complete()
if (album.songs!!.isEmpty()) {
finish()
return
}
this.album = album this.album = album
albumTitle.text = album.title albumTitle.text = album.title
if (MusicUtil.getYearString(album.year) == "-") { if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format( albumText.text = String.format("%s", album.artist)
"%s • %s",
album.artistName,
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
} else { } else {
albumText.text = String.format( albumText.text = String.format("%s • %s", album.artist, MusicUtil.getYearString(album.year))
"%s • %s • %s",
album.artistName,
MusicUtil.getYearString(album.year),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
} }
loadAlbumCover() loadAlbumCover()
simpleSongAdapter.swapDataSet(album.songs) albumDetailsPresenter.albumSongs(album.id)
albumDetailsPresenter.loadMore(album.artistId) albumDetailsPresenter.loadMore(album.artistId)
albumDetailsPresenter.aboutAlbum(album.artistName!!, album.title!!) albumDetailsPresenter.aboutAlbum(album.artist, album.title)
} }
override fun moreAlbums(albums: ArrayList<Album>) { override fun songs(songs: List<Song>) {
this.songs = songs
simpleSongAdapter.swapDataSet(songs)
}
override fun moreAlbums(albums: List<Album>) {
moreTitle.show() moreTitle.show()
moreRecyclerView.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) val albumAdapter = HorizontalAlbumAdapter(this, albums, null)
moreRecyclerView.layoutManager = GridLayoutManager( moreRecyclerView.layoutManager = GridLayoutManager(
this, this,
1, 1,
@ -250,19 +239,23 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
} }
override fun loadArtistImage(artist: Artist) { override fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build() ArtistGlideRequest.Builder.from(Glide.with(this), artist)
.dontAnimate().dontTransform().into(object : RetroMusicColoredTarget(artistImage) { .generatePalette(this)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
} }
}) })
} }
private fun loadAlbumCover() { private fun loadAlbumCover() {
SongGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong()) AlbumGlideRequest.Builder(Glide.with(this), album.id)
.checkIgnoreMediaStore(this)
.ignoreMediaStore(PreferenceUtil.getInstance(this).ignoreMediaStoreArtwork())
.generatePalette(this) .generatePalette(this)
.build().dontAnimate().dontTransform() .build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(image) { .into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
setColors(color) setColors(color)
@ -362,16 +355,18 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
private fun setUpSortOrderMenu(sortOrder: SubMenu) { private fun setUpSortOrderMenu(sortOrder: SubMenu) {
when (savedSortOrder) { when (savedSortOrder) {
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true AlbumSongSortOrder.SONG_A_Z ->
AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true sortOrder.findItem(R.id.action_sort_order_title).isChecked = true
AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list).isChecked = AlbumSongSortOrder.SONG_Z_A ->
true sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true
AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration) AlbumSongSortOrder.SONG_TRACK_LIST ->
.isChecked = true sortOrder.findItem(R.id.action_sort_order_track_list).isChecked = true
AlbumSongSortOrder.SONG_DURATION ->
sortOrder.findItem(R.id.action_sort_order_artist_song_duration).isChecked = true
} }
} }
private fun setSaveSortOrder(sortOrder: String?) { private fun setSaveSortOrder(sortOrder: String) {
PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder
reload() reload()
} }
@ -383,7 +378,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
private fun reload() { private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) { 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 { } else {
finish() finish()
} }

View file

@ -29,7 +29,9 @@ import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder 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.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView
import code.name.monkey.retromusic.rest.model.LastFmArtist import code.name.monkey.retromusic.rest.model.LastFmArtist
@ -57,7 +59,6 @@ import kotlinx.android.synthetic.main.activity_artist_details.artistTitle
import kotlinx.android.synthetic.main.activity_artist_details.image import kotlinx.android.synthetic.main.activity_artist_details.image
import kotlinx.android.synthetic.main.activity_artist_details.text import kotlinx.android.synthetic.main.activity_artist_details.text
import kotlinx.android.synthetic.main.activity_artist_details.toolbar import kotlinx.android.synthetic.main.activity_artist_details.toolbar
import java.text.DecimalFormat
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@ -84,6 +85,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
private var cab: MaterialCab? = null private var cab: MaterialCab? = null
private var biography: Spanned? = null private var biography: Spanned? = null
private lateinit var artist: Artist private lateinit var artist: Artist
private lateinit var songs: List<Song>
private lateinit var songAdapter: SimpleSongAdapter private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: HorizontalAlbumAdapter private lateinit var albumAdapter: HorizontalAlbumAdapter
private var forceDownload: Boolean = false private var forceDownload: Boolean = false
@ -118,7 +120,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
artistDetailsPresenter.attachView(this) artistDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) { if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { intent.extras?.getLong(EXTRA_ARTIST_ID)?.let {
artistDetailsPresenter.loadArtist(it) artistDetailsPresenter.loadArtist(it)
val name = "${getString(R.string.transition_artist_image)}_$it" val name = "${getString(R.string.transition_artist_image)}_$it"
artistCoverContainer?.transitionName = name artistCoverContainer?.transitionName = name
@ -133,10 +135,10 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
setupRecyclerView() setupRecyclerView()
playAction.apply { playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) } setOnClickListener { MusicPlayerRemote.openQueue(songs, 0, true) }
} }
shuffleAction.apply { shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) } setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(songs, true) }
} }
biographyText.setOnClickListener { biographyText.setOnClickListener {
@ -154,7 +156,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), false, null) albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), null)
albumRecyclerView.apply { albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false) layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
@ -189,6 +191,15 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
ActivityCompat.startPostponedEnterTransition(this) ActivityCompat.startPostponedEnterTransition(this)
} }
override fun songs(songs: List<Song>) {
this.songs = songs
songAdapter.swapDataSet(songs)
}
override fun albums(albums: List<Album>) {
albumAdapter.swapDataSet(ArrayList(albums))
}
override fun artist(artist: Artist) { override fun artist(artist: Artist) {
complete() complete()
if (artist.songCount <= 0) { if (artist.songCount <= 0) {
@ -202,13 +213,11 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
} }
artistTitle.text = artist.name artistTitle.text = artist.name
text.text = String.format( text.text = String.format(
"%s • %s", "%s",
MusicUtil.getArtistInfoString(this, artist), MusicUtil.getArtistInfoString(this, artist)
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
) )
artistDetailsPresenter.loadArtistAlbums(artist.id)
songAdapter.swapDataSet(artist.songs) artistDetailsPresenter.loadArtistSongs(artist.id)
albumAdapter.swapDataSet(artist.albums!!)
} }
private fun loadBiography( private fun loadBiography(
@ -281,30 +290,17 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
MaterialUtil.setTint(button = playAction, color = buttonColor) MaterialUtil.setTint(button = playAction, color = buttonColor)
val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface) val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
//status_bar.setBackgroundColor(toolbarColor)
toolbar.setBackgroundColor(toolbarColor) toolbar.setBackgroundColor(toolbarColor)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.title = null supportActionBar?.title = null
} }
private fun numberFormat(count: Float): String {
val prefixes = arrayOf("", "K", "M", "B", "T", "P", "E")
var index = 0
var finalCount = count
while (finalCount / 1000 >= 1) {
finalCount /= 1000
index++
}
val decimal = DecimalFormat("#.##")
return String.format("%s %s", decimal.format(finalCount), prefixes[index])
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item) return handleSortOrderMenuItem(item)
} }
private fun handleSortOrderMenuItem(item: MenuItem): Boolean { private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
when (item.itemId) { when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
super.onBackPressed() super.onBackPressed()
@ -354,7 +350,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
private fun reload() { private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) { 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 { } else {
finish() finish()
} }

View file

@ -129,7 +129,7 @@ class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDet
}) })
} }
override fun songs(songs: ArrayList<Song>) { override fun songs(songs: List<Song>) {
songAdapter.swapDataSet(songs) songAdapter.swapDataSet(songs)
} }

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.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper import code.name.monkey.retromusic.helper.SearchQueryHelper
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks 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.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater import code.name.monkey.retromusic.util.AppRater
@ -155,14 +153,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
val id = parseIdFromIntent(intent, "albumId", "album").toInt() val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) { if (id >= 0) {
val position = intent.getIntExtra("position", 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 handled = true
} }
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt() val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) { if (id >= 0) {
val position = intent.getIntExtra("position", 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 handled = true
} }
} }
@ -220,7 +218,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == PreferenceUtil.GENERAL_THEME || key == PreferenceUtil.BLACK_THEME || key == PreferenceUtil.ADAPTIVE_COLOR_APP || key == PreferenceUtil.DOMINANT_COLOR || key == PreferenceUtil.USER_NAME || key == PreferenceUtil.TOGGLE_FULL_SCREEN || key == PreferenceUtil.TOGGLE_VOLUME || key == PreferenceUtil.ROUND_CORNERS || key == PreferenceUtil.CAROUSEL_EFFECT || key == PreferenceUtil.NOW_PLAYING_SCREEN_ID || key == PreferenceUtil.TOGGLE_GENRE || key == PreferenceUtil.BANNER_IMAGE_PATH || key == PreferenceUtil.PROFILE_IMAGE_PATH || key == PreferenceUtil.CIRCULAR_ALBUM_ART || key == PreferenceUtil.KEEP_SCREEN_ON || key == PreferenceUtil.TOGGLE_SEPARATE_LINE || key == PreferenceUtil.ALBUM_GRID_STYLE || key == PreferenceUtil.ARTIST_GRID_STYLE || key == PreferenceUtil.TOGGLE_HOME_BANNER || key == PreferenceUtil.TOGGLE_ADD_CONTROLS || key == PreferenceUtil.ALBUM_COVER_STYLE || key == PreferenceUtil.HOME_ARTIST_GRID_STYLE || key == PreferenceUtil.ALBUM_COVER_TRANSFORM || key == PreferenceUtil.DESATURATED_COLOR || key == PreferenceUtil.TAB_TEXT_MODE || key == PreferenceUtil.LIBRARY_CATEGORIES if (key == PreferenceUtil.GENERAL_THEME || key == PreferenceUtil.BLACK_THEME || key == PreferenceUtil.ADAPTIVE_COLOR_APP || key == PreferenceUtil.DOMINANT_COLOR || key == PreferenceUtil.USER_NAME || key == PreferenceUtil.TOGGLE_FULL_SCREEN || key == PreferenceUtil.TOGGLE_VOLUME || key == PreferenceUtil.ROUND_CORNERS || key == PreferenceUtil.CAROUSEL_EFFECT || key == PreferenceUtil.NOW_PLAYING_SCREEN_ID || key == PreferenceUtil.TOGGLE_GENRE || key == PreferenceUtil.BANNER_IMAGE_PATH || key == PreferenceUtil.PROFILE_IMAGE_PATH || key == PreferenceUtil.CIRCULAR_ALBUM_ART || key == PreferenceUtil.KEEP_SCREEN_ON || key == PreferenceUtil.TOGGLE_SEPARATE_LINE || key == PreferenceUtil.TOGGLE_HOME_BANNER || key == PreferenceUtil.TOGGLE_ADD_CONTROLS || key == PreferenceUtil.ALBUM_COVER_STYLE || key == PreferenceUtil.HOME_ARTIST_GRID_STYLE || key == PreferenceUtil.ALBUM_COVER_TRANSFORM || key == PreferenceUtil.DESATURATED_COLOR || key == PreferenceUtil.TAB_TEXT_MODE || key == PreferenceUtil.LIBRARY_CATEGORIES
) postRecreate() ) postRecreate()
} }

View file

@ -238,7 +238,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
emptyText.visibility = View.VISIBLE emptyText.visibility = View.VISIBLE
} }
override fun songs(songs: ArrayList<Song>) { override fun songs(songs: List<Song>) {
adapter.swapDataSet(songs) adapter.swapDataSet(songs)
} }

View file

@ -40,7 +40,7 @@ import java.util.Collections
abstract class AbsTagEditorActivity : AbsBaseActivity() { abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected var id: Int = 0 protected var id: Long = 0
private set private set
private var paletteColorPrimary: Int = 0 private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false private var isInNoImageMode: Boolean = false
@ -187,22 +187,16 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
setUpViews() setUpViews()
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
} }
private fun setUpViews() { private fun setUpViews() {
setUpScrollView()
setUpFab() setUpFab()
setUpImageView() setUpImageView()
} }
private fun setUpScrollView() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
}
private lateinit var items: List<String> private lateinit var items: List<String>
private fun setUpImageView() { private fun setUpImageView() {
@ -261,7 +255,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun getIntentExtras() { private fun getIntentExtras() {
val intentExtras = intent.extras val intentExtras = intent.extras
if (intentExtras != null) { if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID) id = intentExtras.getLong(EXTRA_ID)
} }
} }
@ -406,7 +400,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?) class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
companion object { companion object {
@ -415,5 +409,4 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val TAG = AbsTagEditorActivity::class.java.simpleName private val TAG = AbsTagEditorActivity::class.java.simpleName
private const val REQUEST_CODE_SELECT_IMAGE = 1000 private const val REQUEST_CODE_SELECT_IMAGE = 1000
} }
} }

View file

@ -15,7 +15,6 @@ import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -32,6 +31,8 @@ import kotlinx.android.synthetic.main.activity_album_tag_editor.albumArtistConta
import kotlinx.android.synthetic.main.activity_album_tag_editor.albumArtistText import kotlinx.android.synthetic.main.activity_album_tag_editor.albumArtistText
import kotlinx.android.synthetic.main.activity_album_tag_editor.albumText import kotlinx.android.synthetic.main.activity_album_tag_editor.albumText
import kotlinx.android.synthetic.main.activity_album_tag_editor.albumTitleContainer import kotlinx.android.synthetic.main.activity_album_tag_editor.albumTitleContainer
import kotlinx.android.synthetic.main.activity_album_tag_editor.artistContainer
import kotlinx.android.synthetic.main.activity_album_tag_editor.artistText
import kotlinx.android.synthetic.main.activity_album_tag_editor.genreContainer import kotlinx.android.synthetic.main.activity_album_tag_editor.genreContainer
import kotlinx.android.synthetic.main.activity_album_tag_editor.genreTitle import kotlinx.android.synthetic.main.activity_album_tag_editor.genreTitle
import kotlinx.android.synthetic.main.activity_album_tag_editor.imageContainer import kotlinx.android.synthetic.main.activity_album_tag_editor.imageContainer
@ -39,7 +40,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.yearContainer
import kotlinx.android.synthetic.main.activity_album_tag_editor.yearTitle import kotlinx.android.synthetic.main.activity_album_tag_editor.yearTitle
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.util.ArrayList
import java.util.EnumMap import java.util.EnumMap
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher { class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
@ -58,7 +58,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override fun loadImageFromFile(selectedFileUri: Uri?) { override fun loadImageFromFile(selectedFileUri: Uri?) {
Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap() Glide.with(this@AlbumTagEditorActivity)
.load(selectedFileUri)
.asBitmap()
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java) .transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : SimpleTarget<BitmapPaletteWrapper>() { .into(object : SimpleTarget<BitmapPaletteWrapper>() {
@ -115,15 +117,18 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
MaterialUtil.setTint(genreContainer, false) MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false) MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false) MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(artistContainer, false)
albumText.appHandleColor().addTextChangedListener(this) albumText.addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this) artistText.addTextChangedListener(this)
genreTitle.appHandleColor().addTextChangedListener(this) albumArtistText.addTextChangedListener(this)
yearTitle.appHandleColor().addTextChangedListener(this) genreTitle.addTextChangedListener(this)
yearTitle.addTextChangedListener(this)
} }
private fun fillViewsWithFileTags() { private fun fillViewsWithFileTags() {
albumText.setText(albumTitle) albumText.setText(albumTitle)
artistText.setText(artistName)
albumArtistText.setText(albumArtistName) albumArtistText.setText(albumArtistName)
genreTitle.setText(genreName) genreTitle.setText(genreName)
yearTitle.setText(songYear) yearTitle.setText(songYear)
@ -141,10 +146,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
deleteAlbumArt = false deleteAlbumArt = false
} }
override fun onPause() {
super.onPause()
}
private fun toastLoadingFailed() { private fun toastLoadingFailed() {
Toast.makeText( Toast.makeText(
this@AlbumTagEditorActivity, this@AlbumTagEditorActivity,
@ -170,21 +171,24 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java) val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString() fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
//android seems not to recognize album_artist field so we additionally write the normal artist field //android seems not to recognize album_artist field so we additionally write the normal artist field
fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString() fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString() fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString() fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString() fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString()
writeValuesToFiles( writeValuesToFiles(
fieldKeyValueMap, fieldKeyValueMap,
if (deleteAlbumArt) ArtworkInfo(id, null) when {
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!) deleteAlbumArt -> ArtworkInfo(id, null)
albumArtBitmap == null -> null
else -> ArtworkInfo(id, albumArtBitmap!!)
}
) )
} }
override fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> {
val songs = AlbumLoader.getAlbum(this, id).songs val songs = AlbumLoader.getSongsForAlbum(this, id)
val paths = ArrayList<String>(songs!!.size) val paths = ArrayList<String>(songs.size)
for (song in songs) { for (song in songs) {
paths.add(song.data) paths.add(song.data)
} }
@ -207,7 +211,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
} }
companion object { companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName val TAG: String = AlbumTagEditorActivity::class.java.simpleName
} }
} }

View file

@ -6,7 +6,6 @@ import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import code.name.monkey.appthemehelper.util.MaterialUtil import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.loaders.SongLoader import code.name.monkey.retromusic.loaders.SongLoader
import kotlinx.android.synthetic.main.activity_song_tag_editor.albumArtistContainer import kotlinx.android.synthetic.main.activity_song_tag_editor.albumArtistContainer
@ -43,7 +42,6 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
setNoImageMode() setNoImageMode()
setUpViews() setUpViews()
applyToolbar(toolbar) applyToolbar(toolbar)
} }
private fun setUpViews() { private fun setUpViews() {
@ -58,15 +56,15 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
MaterialUtil.setTint(trackNumberContainer, false) MaterialUtil.setTint(trackNumberContainer, false)
MaterialUtil.setTint(lyricsContainer, false) MaterialUtil.setTint(lyricsContainer, false)
songText.appHandleColor().addTextChangedListener(this) songText.addTextChangedListener(this)
albumText.appHandleColor().addTextChangedListener(this) albumText.addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this) albumArtistText.addTextChangedListener(this)
artistText.appHandleColor().addTextChangedListener(this) artistText.addTextChangedListener(this)
genreText.appHandleColor().addTextChangedListener(this) genreText.addTextChangedListener(this)
yearText.appHandleColor().addTextChangedListener(this) yearText.addTextChangedListener(this)
trackNumberText.appHandleColor().addTextChangedListener(this) trackNumberText.addTextChangedListener(this)
lyricsText.appHandleColor().addTextChangedListener(this) lyricsText.addTextChangedListener(this)
songComposerText.appHandleColor().addTextChangedListener(this) songComposerText.addTextChangedListener(this)
} }
private fun fillViewsWithFileTags() { private fun fillViewsWithFileTags() {

View file

@ -9,7 +9,6 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import java.util.ArrayList
import java.util.Locale import java.util.Locale
/** /**
@ -18,11 +17,11 @@ import java.util.Locale
class GenreAdapter( class GenreAdapter(
private val activity: Activity, private val activity: Activity,
dataSet: ArrayList<Genre>, dataSet: List<Genre>,
private val mItemLayoutRes: Int private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() { ) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
var dataSet = ArrayList<Genre>() var dataSet = listOf<Genre>()
private set private set
init { init {
@ -48,7 +47,7 @@ class GenreAdapter(
return dataSet.size return dataSet.size
} }
fun swapDataSet(list: ArrayList<Genre>) { fun swapDataSet(list: List<Genre>) {
dataSet = list dataSet = list
notifyDataSetChanged() notifyDataSetChanged()
} }

View file

@ -52,7 +52,6 @@ class HomeAdapter(
} }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
println("ViewType ${getItemViewType(position)}")
when (getItemViewType(position)) { when (getItemViewType(position)) {
RECENT_ALBUMS -> { RECENT_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder val viewHolder = holder as AlbumViewHolder
@ -121,7 +120,6 @@ class HomeAdapter(
activity, activity,
list, list,
PreferenceUtil.getInstance(activity).getHomeGridStyle(activity), PreferenceUtil.getInstance(activity).getHomeGridStyle(activity),
false,
null null
) )
adapter = artistAdapter adapter = artistAdapter

View file

@ -9,8 +9,9 @@ import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.SongGlideRequest import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
@ -60,9 +61,18 @@ class SearchAdapter(
ALBUM -> { ALBUM -> {
val album = dataSet?.get(position) as Album val album = dataSet?.get(position) as Album
holder.title?.text = album.title holder.title?.text = album.title
holder.text?.text = album.artistName holder.text?.text = album.artist
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) holder.image?.let {
.checkIgnoreMediaStore(activity).build().into(holder.image) AlbumGlideRequest.Builder(Glide.with(activity), album.id)
.generatePalette(activity)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(it) {
override fun onColorReady(color: Int) {
}
})
}
} }
ARTIST -> { ARTIST -> {
val artist = dataSet?.get(position) as Artist val artist = dataSet?.get(position) as Artist
@ -134,21 +144,24 @@ class SearchAdapter(
val item = dataSet!![adapterPosition] val item = dataSet!![adapterPosition]
when (itemViewType) { when (itemViewType) {
ALBUM -> { ALBUM -> {
item as Album
val options = ActivityOptions.makeSceneTransitionAnimation( val options = ActivityOptions.makeSceneTransitionAnimation(
activity, activity,
UtilPair.create(image, activity.getString(R.string.transition_album_art)) UtilPair.create(image, activity.getString(R.string.transition_album_art))
) )
NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options) NavigationUtil.goToAlbumOptions(activity, item.id, options)
} }
ARTIST -> { ARTIST -> {
item as Artist
val options = ActivityOptions.makeSceneTransitionAnimation( val options = ActivityOptions.makeSceneTransitionAnimation(
activity, activity,
UtilPair.create(image, activity.getString(R.string.transition_artist_image)) UtilPair.create(image, activity.getString(R.string.transition_artist_image))
) )
NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options) NavigationUtil.goToArtistOptions(activity, item.id, options)
} }
GENRE -> { GENRE -> {
NavigationUtil.goToGenre(activity, item as Genre) item as Genre
NavigationUtil.goToGenre(activity, item)
} }
PLAYLIST -> { PLAYLIST -> {
NavigationUtil.goToPlaylistNew(activity, item as Playlist) NavigationUtil.goToPlaylistNew(activity, item as Playlist)

View file

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

View file

@ -22,9 +22,8 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import code.name.monkey.retromusic.R 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.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.model.Album
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.views.MetalRecyclerViewPager import code.name.monkey.retromusic.views.MetalRecyclerViewPager
@ -46,15 +45,6 @@ class AlbumFullWidthAdapter(
val album = dataSet[position] val album = dataSet[position]
holder.title?.text = getAlbumTitle(album) holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album) holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs?.let { songs ->
MusicPlayerRemote.openQueue(
songs,
0,
true
)
}
}
loadAlbumCover(album, holder) loadAlbumCover(album, holder)
} }
@ -63,21 +53,32 @@ class AlbumFullWidthAdapter(
} }
private fun getAlbumText(album: Album): String? { private fun getAlbumText(album: Album): String? {
return album.artistName return album.artist
} }
private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) { private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) {
if (holder.image == null) { if (holder.image == null) {
return 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) .checkIgnoreMediaStore(activity)
.generatePalette(activity) .generatePalette(activity)
.build() .build()
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
} }
}) })*/
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {

View file

@ -1,26 +1,23 @@
package code.name.monkey.retromusic.adapter.album package code.name.monkey.retromusic.adapter.album
import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ATHUtil 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.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import java.util.ArrayList
class HorizontalAlbumAdapter( class HorizontalAlbumAdapter(
activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: ArrayList<Album>, dataSet: List<Album>,
usePalette: Boolean,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AlbumAdapter( ) : AlbumAdapter(
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder
) { ) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder { override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -36,17 +33,14 @@ class HorizontalAlbumAdapter(
override fun loadAlbumCover(album: Album, holder: ViewHolder) { override fun loadAlbumCover(album: Album, holder: ViewHolder) {
if (holder.image == null) return if (holder.image == null) return
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) AlbumGlideRequest.Builder(Glide.with(activity), album.id)
.checkIgnoreMediaStore(activity).generatePalette(activity).build() .generatePalette(activity)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(holder.image!!) { .into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(albumArtistFooterColor, holder)
}
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
if (usePalette) setColors(color, holder) //setColors(color, holder)
else setColors(albumArtistFooterColor, holder)
} }
}) })
} }

View file

@ -28,26 +28,20 @@ import java.util.ArrayList
class ArtistAdapter( class ArtistAdapter(
val activity: AppCompatActivity, val activity: AppCompatActivity,
var dataSet: ArrayList<Artist>, var dataSet: List<Artist>,
var itemLayoutRes: Int, var itemLayoutRes: Int,
var usePalette: Boolean,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>( ) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
activity, cabHolder, R.menu.menu_media_selection activity, cabHolder, R.menu.menu_media_selection
), PopupTextProvider { ), PopupTextProvider {
fun swapDataSet(dataSet: ArrayList<Artist>) { fun swapDataSet(dataSet: List<Artist>) {
this.dataSet = dataSet this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }
fun usePalette(usePalette: Boolean) {
this.usePalette = usePalette
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong() return dataSet[position].id
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -121,7 +115,7 @@ class ArtistAdapter(
private fun getSongList(artists: List<Artist>): ArrayList<Song> { private fun getSongList(artists: List<Artist>): ArrayList<Song> {
val songs = ArrayList<Song>() val songs = ArrayList<Song>()
for (artist in artists) { for (artist in artists) {
songs.addAll(artist.songs) // maybe async in future? //songs.addAll(artist.songs) // maybe async in future?
} }
return songs return songs
} }

View file

@ -17,7 +17,6 @@ package code.name.monkey.retromusic.adapter.base;
import android.graphics.Color; import android.graphics.Color;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -60,8 +59,6 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
@Nullable @Nullable
public View paletteColorContainer; public View paletteColorContainer;
@Nullable
public ImageButton playSongs;
@Nullable @Nullable
public RecyclerView recyclerView; public RecyclerView recyclerView;
@ -93,7 +90,6 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer); paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
recyclerView = itemView.findViewById(R.id.recycler_view); recyclerView = itemView.findViewById(R.id.recycler_view);
mask = itemView.findViewById(R.id.mask); mask = itemView.findViewById(R.id.mask);
playSongs = itemView.findViewById(R.id.playSongs);
dummyContainer = itemView.findViewById(R.id.dummy_view); dummyContainer = itemView.findViewById(R.id.dummy_view);
if (imageContainerCard != null) { if (imageContainerCard != null) {

View file

@ -34,7 +34,7 @@ import java.util.ArrayList
class PlaylistAdapter( class PlaylistAdapter(
private val activity: AppCompatActivity, private val activity: AppCompatActivity,
var dataSet: ArrayList<Playlist>, var dataSet: List<Playlist>,
private var itemLayoutRes: Int, private var itemLayoutRes: Int,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>( ) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(
@ -49,7 +49,7 @@ class PlaylistAdapter(
setHasStableIds(true) setHasStableIds(true)
} }
fun swapDataSet(dataSet: ArrayList<Playlist>) { fun swapDataSet(dataSet: List<Playlist>) {
this.dataSet = dataSet this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }

View file

@ -9,11 +9,10 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import java.util.ArrayList
abstract class AbsOffsetSongAdapter( abstract class AbsOffsetSongAdapter(
activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: ArrayList<Song>, dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int, @LayoutRes itemLayoutRes: Int,
cabHolder: CabHolder? cabHolder: CabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { ) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {

View file

@ -63,7 +63,7 @@ open class PlaylistSongAdapter(
imageContainerCard ?: image, imageContainerCard ?: image,
"${activity.getString(R.string.transition_album_art)}_${song.albumId}" "${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 true
} }
return super.onSongMenuItemClick(item) return super.onSongMenuItemClick(item)

View file

@ -7,11 +7,10 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import java.util.ArrayList
class ShuffleButtonSongAdapter( class ShuffleButtonSongAdapter(
activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: ArrayList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { ) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {

View file

@ -6,18 +6,16 @@ import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import java.util.ArrayList
class SimpleSongAdapter( class SimpleSongAdapter(
context: AppCompatActivity, context: AppCompatActivity,
songs: ArrayList<Song>, songs: MutableList<Song>,
layoutRes: Int, layoutRes: Int,
cabHolder: CabHolder? cabHolder: CabHolder?
) : SongAdapter(context, songs, layoutRes, cabHolder) { ) : SongAdapter(context, songs, layoutRes, cabHolder) {
override fun swapDataSet(dataSet: ArrayList<Song>) { override fun swapDataSet(dataSet: List<Song>) {
this.dataSet.clear() this.dataSet = dataSet.toMutableList()
this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }

View file

@ -34,7 +34,7 @@ import java.util.ArrayList
open class SongAdapter( open class SongAdapter(
protected val activity: AppCompatActivity, protected val activity: AppCompatActivity,
dataSet: ArrayList<Song>, dataSet: MutableList<Song>,
protected var itemLayoutRes: Int, protected var itemLayoutRes: Int,
cabHolder: CabHolder?, cabHolder: CabHolder?,
showSectionName: Boolean = true showSectionName: Boolean = true
@ -42,7 +42,7 @@ open class SongAdapter(
activity, cabHolder, R.menu.menu_media_selection activity, cabHolder, R.menu.menu_media_selection
), MaterialCab.Callback, PopupTextProvider { ), MaterialCab.Callback, PopupTextProvider {
var dataSet: ArrayList<Song> var dataSet: MutableList<Song>
private var showSectionName = true private var showSectionName = true
init { init {
@ -51,8 +51,8 @@ open class SongAdapter(
this.setHasStableIds(true) this.setHasStableIds(true)
} }
open fun swapDataSet(dataSet: ArrayList<Song>) { open fun swapDataSet(dataSet: List<Song>) {
this.dataSet = dataSet this.dataSet = dataSet.toMutableList()
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -177,7 +177,7 @@ open class SongAdapter(
imageContainerCard ?: image, imageContainerCard ?: image,
"${activity.getString(R.string.transition_album_art)}_${song.albumId}" "${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 true
} }
} }

View file

@ -27,11 +27,10 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems import com.afollestad.materialdialogs.list.listItems
class AddToPlaylistDialog : DialogFragment() { class AddToPlaylistDialog : DialogFragment() {
override fun onCreateDialog( override fun onCreateDialog(
savedInstanceState: Bundle? savedInstanceState: Bundle?
): Dialog { ): Dialog {
val playlists = PlaylistLoader.getAllPlaylists(requireContext()) val playlists = PlaylistLoader.getAllPlaylists(requireContext())
val playlistNames: MutableList<String> = mutableListOf() val playlistNames: MutableList<String> = mutableListOf()
@ -47,7 +46,9 @@ class AddToPlaylistDialog : DialogFragment() {
val songs = arguments!!.getParcelableArrayList<Song>("songs") ?: return@listItems val songs = arguments!!.getParcelableArrayList<Song>("songs") ?: return@listItems
if (index == 0) { if (index == 0) {
dialog.dismiss() dialog.dismiss()
activity?.supportFragmentManager?.let { CreatePlaylistDialog.create(songs).show(it, "ADD_TO_PLAYLIST") } activity?.supportFragmentManager?.let {
CreatePlaylistDialog.create(songs).show(it, "ADD_TO_PLAYLIST")
}
} else { } else {
dialog.dismiss() dialog.dismiss()
PlaylistsUtil.addToPlaylist(requireContext(), songs, playlists[index - 1].id, true) PlaylistsUtil.addToPlaylist(requireContext(), songs, playlists[index - 1].id, true)
@ -64,10 +65,10 @@ class AddToPlaylistDialog : DialogFragment() {
return create(list) return create(list)
} }
fun create(songs: ArrayList<Song>): AddToPlaylistDialog { fun create(songs: List<Song>): AddToPlaylistDialog {
val dialog = AddToPlaylistDialog() val dialog = AddToPlaylistDialog()
val args = Bundle() val args = Bundle()
args.putParcelableArrayList("songs", songs) args.putParcelableArrayList("songs", ArrayList(songs))
dialog.arguments = args dialog.arguments = args
return dialog return dialog
} }

View file

@ -29,8 +29,8 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems import com.afollestad.materialdialogs.list.listItems
import java.io.File import java.io.File
import java.util.* import java.util.Collections
import kotlin.collections.ArrayList import java.util.Comparator
class BlacklistFolderChooserDialog : DialogFragment() { class BlacklistFolderChooserDialog : DialogFragment() {
@ -40,7 +40,6 @@ class BlacklistFolderChooserDialog : DialogFragment() {
private var canGoUp = false private var canGoUp = false
private var callback: FolderCallback? = null private var callback: FolderCallback? = null
private fun contentsArray(): List<String> { private fun contentsArray(): List<String> {
if (parentContents == null) { if (parentContents == null) {
return if (canGoUp) { return if (canGoUp) {
@ -81,7 +80,11 @@ class BlacklistFolderChooserDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
var savedInstanceStateFinal = savedInstanceState var savedInstanceStateFinal = savedInstanceState
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
ActivityCompat.checkSelfPermission(requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
return MaterialDialog(requireActivity(), BottomSheet(LayoutMode.WRAP_CONTENT)).show { return MaterialDialog(requireActivity(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(R.string.md_error_label) title(R.string.md_error_label)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner) cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)

View file

@ -23,7 +23,6 @@ import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.R.layout import code.name.monkey.retromusic.R.layout
import code.name.monkey.retromusic.R.string import code.name.monkey.retromusic.R.string
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PlaylistsUtil import code.name.monkey.retromusic.util.PlaylistsUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -35,36 +34,35 @@ import com.afollestad.materialdialogs.customview.getCustomView
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
class CreatePlaylistDialog : DialogFragment() { class CreatePlaylistDialog : DialogFragment() {
private lateinit var playlistView: TextInputEditText private lateinit var playlistView: TextInputEditText
private lateinit var actionNewPlaylistContainer: TextInputLayout private lateinit var actionNewPlaylistContainer: TextInputLayout
override fun onCreateDialog( override fun onCreateDialog(
savedInstanceState: Bundle? savedInstanceState: Bundle?
): Dialog { ): Dialog {
val materialDialog = MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)) val materialDialog = MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT))
.show { .show {
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner) cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
title(string.new_playlist_title) title(string.new_playlist_title)
customView(layout.dialog_playlist) customView(layout.dialog_playlist)
negativeButton(android.R.string.cancel) negativeButton(android.R.string.cancel)
positiveButton(string.create_action) { positiveButton(string.create_action) {
if (activity == null) { if (activity == null) {
return@positiveButton return@positiveButton
} }
val songs = arguments?.getParcelableArrayList<Song>("songs") val songs = arguments?.getParcelableArrayList<Song>("songs")
?: return@positiveButton ?: return@positiveButton
if (playlistView.text.toString().trim { it <= ' ' }.isNotEmpty()) { if (playlistView.text.toString().trim { it <= ' ' }.isNotEmpty()) {
val playlistId = PlaylistsUtil.createPlaylist(requireContext(), playlistView.text.toString()) val playlistId = PlaylistsUtil.createPlaylist(requireContext(), playlistView.text.toString())
if (playlistId != -1 && activity != null) { if (playlistId != -1 && activity != null) {
PlaylistsUtil.addToPlaylist(requireContext(), songs, playlistId, true) PlaylistsUtil.addToPlaylist(requireContext(), songs, playlistId, true)
}
} }
} }
} }
}
val dialogView = materialDialog.getCustomView() val dialogView = materialDialog.getCustomView()
playlistView = dialogView.findViewById(R.id.actionNewPlaylist) playlistView = dialogView.findViewById(R.id.actionNewPlaylist)
@ -73,7 +71,10 @@ class CreatePlaylistDialog : DialogFragment() {
MaterialUtil.setTint(actionNewPlaylistContainer, false) MaterialUtil.setTint(actionNewPlaylistContainer, false)
val playlistId = arguments!!.getLong(MediaStore.Audio.Playlists.Members.PLAYLIST_ID) val playlistId = arguments!!.getLong(MediaStore.Audio.Playlists.Members.PLAYLIST_ID)
playlistView.appHandleColor().setText(PlaylistsUtil.getNameForPlaylist(requireContext(), playlistId), TextView.BufferType.EDITABLE) playlistView.setText(
PlaylistsUtil.getNameForPlaylist(requireContext(), playlistId),
TextView.BufferType.EDITABLE
)
return materialDialog return materialDialog
} }

View file

@ -104,10 +104,10 @@ class DeleteSongsDialog : DialogFragment() {
return create(list) return create(list)
} }
fun create(songs: ArrayList<Song>): DeleteSongsDialog { fun create(songs: List<Song>): DeleteSongsDialog {
val dialog = DeleteSongsDialog() val dialog = DeleteSongsDialog()
val args = Bundle() val args = Bundle()
args.putParcelableArrayList("songs", songs) args.putParcelableArrayList("songs", ArrayList(songs))
dialog.arguments = args dialog.arguments = args
return dialog return dialog
} }

View file

@ -23,7 +23,6 @@ import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.R.layout import code.name.monkey.retromusic.R.layout
import code.name.monkey.retromusic.R.string import code.name.monkey.retromusic.R.string
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.util.PlaylistsUtil import code.name.monkey.retromusic.util.PlaylistsUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.LayoutMode import com.afollestad.materialdialogs.LayoutMode
@ -60,7 +59,7 @@ class RenamePlaylistDialog : DialogFragment() {
MaterialUtil.setTint(actionNewPlaylistContainer, false) MaterialUtil.setTint(actionNewPlaylistContainer, false)
val playlistId = arguments!!.getLong(PLAYLIST_ID) val playlistId = arguments!!.getLong(PLAYLIST_ID)
playlistView.appHandleColor() playlistView
.setText(PlaylistsUtil.getNameForPlaylist(context!!, playlistId), TextView.BufferType.EDITABLE) .setText(PlaylistsUtil.getNameForPlaylist(context!!, playlistId), TextView.BufferType.EDITABLE)
return materialDialog return materialDialog
} }

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

@ -17,11 +17,7 @@ package code.name.monkey.retromusic.extensions
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.TintHelper
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T { fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T {
@ -41,8 +37,3 @@ fun View.hidden() {
} }
fun View.showOrHide(show: Boolean) = if (show) show() else hide() fun View.showOrHide(show: Boolean) = if (show) show() else hide()
fun EditText.appHandleColor(): EditText {
TintHelper.colorHandles(this, ThemeStore.accentColor(context))
return this
}

View file

@ -10,21 +10,19 @@ enum class NowPlayingScreen constructor(
@param:DrawableRes @field:DrawableRes val drawableResId: Int, @param:DrawableRes @field:DrawableRes val drawableResId: Int,
val id: Int val id: Int
) { ) {
NORMAL(R.string.normal, R.drawable.np_normal, 0),
FLAT(R.string.flat, R.drawable.np_flat, 1),
FIT(R.string.fit, R.drawable.np_fit, 12),
TINY(R.string.tiny, R.drawable.np_tiny, 7),
PEAK(R.string.peak, R.drawable.np_peak, 14),
ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10), ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10),
BLUR(R.string.blur, R.drawable.np_blur, 4), BLUR(R.string.blur, R.drawable.np_blur, 4),
BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9), BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9),
CARD(R.string.card, R.drawable.np_card, 6), CARD(R.string.card, R.drawable.np_card, 6),
COLOR(R.string.color, R.drawable.np_color, 5), COLOR(R.string.color, R.drawable.np_color, 5),
CIRCLE(R.string.circle, R.drawable.np_minimalistic_circle, 15), CIRCLE(R.string.circle, R.drawable.np_minimalistic_circle, 15),
FIT(R.string.fit, R.drawable.np_fit, 12),
FLAT(R.string.flat, R.drawable.np_flat, 1),
FULL(R.string.full, R.drawable.np_full, 2), FULL(R.string.full, R.drawable.np_full, 2),
MATERIAL(R.string.material, R.drawable.np_material, 11), MATERIAL(R.string.material, R.drawable.np_material, 11),
NORMAL(R.string.normal, R.drawable.np_normal, 0),
PEAK(R.string.peak, R.drawable.np_peak, 14),
PLAIN(R.string.plain, R.drawable.np_plain, 3), PLAIN(R.string.plain, R.drawable.np_plain, 3),
SIMPLE(R.string.simple, R.drawable.np_simple, 8), SIMPLE(R.string.simple, R.drawable.np_simple, 8),
TINY(R.string.tiny, R.drawable.np_tiny, 7),
} }

View file

@ -34,6 +34,7 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A : RecyclerVie
fun setAndSaveLayoutRes(layoutRes: Int) { fun setAndSaveLayoutRes(layoutRes: Int) {
setLayoutRes(layoutRes) setLayoutRes(layoutRes)
saveLayoutRes(layoutRes) saveLayoutRes(layoutRes)
invalidateAdapter()
} }
private val maxGridSizeForList: Int private val maxGridSizeForList: Int
@ -118,12 +119,6 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A : RecyclerVie
protected abstract fun saveGridSizeLand(gridColumns: Int) protected abstract fun saveGridSizeLand(gridColumns: Int)
protected abstract fun saveUsePalette(usePalette: Boolean)
protected abstract fun loadUsePalette(): Boolean
protected abstract fun setUsePalette(usePalette: Boolean)
protected abstract fun loadLayoutRes(): Int protected abstract fun loadLayoutRes(): Int
protected abstract fun saveLayoutRes(layoutRes: Int) protected abstract fun saveLayoutRes(layoutRes: Int)

View file

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

View file

@ -41,7 +41,7 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Al
albumsPresenter.detachView() albumsPresenter.detachView()
} }
override fun albums(albums: java.util.ArrayList<Album>) { override fun albums(albums: List<Album>) {
adapter?.swapDataSet(albums) adapter?.swapDataSet(albums)
} }
@ -53,21 +53,13 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Al
} }
override fun createAdapter(): AlbumAdapter { override fun createAdapter(): AlbumAdapter {
/* var itemLayoutRes = itemLayoutRes
notifyLayoutResChanged(itemLayoutRes)
if (itemLayoutRes != R.layout.item_list) {
itemLayoutRes = PreferenceUtil.getInstance(requireContext()).getAlbumGridStyle(requireContext())
}*/
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return AlbumAdapter(libraryFragment.mainActivity, dataSet, itemLayoutRes(), loadUsePalette(), libraryFragment) return AlbumAdapter(
} libraryFragment.mainActivity,
dataSet,
public override fun loadUsePalette(): Boolean { itemLayoutRes(),
return PreferenceUtil.getInstance(requireContext()).albumColoredFooters() libraryFragment
} )
override fun setUsePalette(usePalette: Boolean) {
adapter?.usePalette(usePalette)
} }
override fun setGridSize(gridSize: Int) { override fun setGridSize(gridSize: Int) {
@ -99,10 +91,6 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Al
PreferenceUtil.getInstance(requireContext()).setAlbumGridSizeLand(gridColumns) PreferenceUtil.getInstance(requireContext()).setAlbumGridSizeLand(gridColumns)
} }
override fun saveUsePalette(usePalette: Boolean) {
PreferenceUtil.getInstance(requireContext()).setAlbumColoredFooters(usePalette)
}
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
albumsPresenter.loadAlbums() albumsPresenter.loadAlbums()
} }
@ -116,7 +104,6 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Al
} }
override fun setLayoutRes(layoutRes: Int) { override fun setLayoutRes(layoutRes: Int) {
//adapter?.itemCount?.let { adapter?.notifyItemRangeChanged(0, it) }
} }
override fun loadLayoutRes(): Int { override fun loadLayoutRes(): Int {

View file

@ -16,7 +16,7 @@ import javax.inject.Inject
class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(), class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
ArtistsView { ArtistsView {
override fun artists(artists: ArrayList<Artist>) { override fun artists(artists: List<Artist>) {
adapter?.swapDataSet(artists) adapter?.swapDataSet(artists)
} }
@ -66,7 +66,6 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
libraryFragment.mainActivity, libraryFragment.mainActivity,
dataSet, dataSet,
itemLayoutRes(), itemLayoutRes(),
loadUsePalette(),
libraryFragment libraryFragment
) )
} }
@ -87,18 +86,6 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
PreferenceUtil.getInstance(requireContext()).setArtistGridSizeLand(gridColumns) PreferenceUtil.getInstance(requireContext()).setArtistGridSizeLand(gridColumns)
} }
override fun saveUsePalette(usePalette: Boolean) {
PreferenceUtil.getInstance(requireContext()).setArtistColoredFooters(usePalette)
}
public override fun loadUsePalette(): Boolean {
return PreferenceUtil.getInstance(requireContext()).artistColoredFooters()
}
override fun setUsePalette(usePalette: Boolean) {
adapter?.usePalette(usePalette)
}
override fun setGridSize(gridSize: Int) { override fun setGridSize(gridSize: Int) {
layoutManager?.spanCount = gridSize layoutManager?.spanCount = gridSize
adapter?.notifyDataSetChanged() adapter?.notifyDataSetChanged()
@ -121,9 +108,7 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
val TAG: String = ArtistsFragment::class.java.simpleName val TAG: String = ArtistsFragment::class.java.simpleName
fun newInstance(): ArtistsFragment { fun newInstance(): ArtistsFragment {
val args = Bundle() val args = Bundle()
val fragment = ArtistsFragment() val fragment = ArtistsFragment()
fragment.arguments = args fragment.arguments = args
return fragment return fragment

View file

@ -26,14 +26,12 @@ import code.name.monkey.retromusic.mvp.presenter.GenresPresenter
import code.name.monkey.retromusic.mvp.presenter.GenresView import code.name.monkey.retromusic.mvp.presenter.GenresView
import javax.inject.Inject import javax.inject.Inject
class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(), GenresView { class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(), GenresView {
override fun genres(genres: ArrayList<Genre>) { override fun genres(genres: List<Genre>) {
adapter?.swapDataSet(genres) adapter?.swapDataSet(genres)
} }
override fun showEmptyView() { override fun showEmptyView() {
} }
override fun createLayoutManager(): LinearLayoutManager { override fun createLayoutManager(): LinearLayoutManager {
@ -48,11 +46,9 @@ class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearL
override val emptyMessage: Int override val emptyMessage: Int
get() = R.string.no_genres get() = R.string.no_genres
@Inject @Inject
lateinit var genresPresenter: GenresPresenter lateinit var genresPresenter: GenresPresenter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
App.musicComponent.inject(this) App.musicComponent.inject(this)
@ -62,6 +58,7 @@ class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearL
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
genresPresenter.attachView(this) genresPresenter.attachView(this)
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (adapter!!.dataSet.isEmpty()) { if (adapter!!.dataSet.isEmpty()) {

View file

@ -1,5 +1,9 @@
package code.name.monkey.retromusic.fragments.mainactivity; package code.name.monkey.retromusic.fragments.mainactivity;
import static code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.SongSortOrder;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
@ -27,7 +31,6 @@ import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog;
import code.name.monkey.retromusic.dialogs.OptionsSheetDialogFragment; import code.name.monkey.retromusic.dialogs.OptionsSheetDialogFragment;
import code.name.monkey.retromusic.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment; import code.name.monkey.retromusic.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment;
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment; import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment;
import code.name.monkey.retromusic.helper.SortOrder;
import code.name.monkey.retromusic.interfaces.CabHolder; import code.name.monkey.retromusic.interfaces.CabHolder;
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks; import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks;
import code.name.monkey.retromusic.util.NavigationUtil; import code.name.monkey.retromusic.util.NavigationUtil;
@ -301,49 +304,52 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
if (fragment instanceof AlbumsFragment) { if (fragment instanceof AlbumsFragment) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_album_sort_order_asc: case R.id.action_album_sort_order_asc:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_A_Z; sortOrder = AlbumSortOrder.ALBUM_A_Z;
break; break;
case R.id.action_album_sort_order_desc: case R.id.action_album_sort_order_desc:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_Z_A; sortOrder = AlbumSortOrder.ALBUM_Z_A;
break; break;
case R.id.action_album_sort_order_artist: case R.id.action_album_sort_order_artist:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_ARTIST; sortOrder = AlbumSortOrder.ALBUM_ARTIST;
break; break;
case R.id.action_album_sort_order_year: case R.id.action_album_sort_order_year:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_YEAR; sortOrder = AlbumSortOrder.ALBUM_YEAR;
break;
case R.id.action_album_sort_num_songs:
sortOrder = AlbumSortOrder.ALBUM_NUMBER_OF_SONGS;
break; break;
} }
} else if (fragment instanceof ArtistsFragment) { } else if (fragment instanceof ArtistsFragment) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_artist_sort_order_asc: case R.id.action_artist_sort_order_asc:
sortOrder = SortOrder.ArtistSortOrder.ARTIST_A_Z; sortOrder = ArtistSortOrder.ARTIST_A_Z;
break; break;
case R.id.action_artist_sort_order_desc: case R.id.action_artist_sort_order_desc:
sortOrder = SortOrder.ArtistSortOrder.ARTIST_Z_A; sortOrder = ArtistSortOrder.ARTIST_Z_A;
break; break;
} }
} else if (fragment instanceof SongsFragment) { } else if (fragment instanceof SongsFragment) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_song_sort_order_asc: case R.id.action_song_sort_order_asc:
sortOrder = SortOrder.SongSortOrder.SONG_A_Z; sortOrder = SongSortOrder.SONG_A_Z;
break; break;
case R.id.action_song_sort_order_desc: case R.id.action_song_sort_order_desc:
sortOrder = SortOrder.SongSortOrder.SONG_Z_A; sortOrder = SongSortOrder.SONG_Z_A;
break; break;
case R.id.action_song_sort_order_artist: case R.id.action_song_sort_order_artist:
sortOrder = SortOrder.SongSortOrder.SONG_ARTIST; sortOrder = SongSortOrder.SONG_ARTIST;
break; break;
case R.id.action_song_sort_order_album: case R.id.action_song_sort_order_album:
sortOrder = SortOrder.SongSortOrder.SONG_ALBUM; sortOrder = SongSortOrder.SONG_ALBUM;
break; break;
case R.id.action_song_sort_order_year: case R.id.action_song_sort_order_year:
sortOrder = SortOrder.SongSortOrder.SONG_YEAR; sortOrder = SongSortOrder.SONG_YEAR;
break; break;
case R.id.action_song_sort_order_date: case R.id.action_song_sort_order_date:
sortOrder = SortOrder.SongSortOrder.SONG_DATE; sortOrder = SongSortOrder.SONG_DATE;
break; break;
case R.id.action_song_sort_order_composer: case R.id.action_song_sort_order_composer:
sortOrder = SortOrder.SongSortOrder.COMPOSER; sortOrder = SongSortOrder.COMPOSER;
break; break;
} }
@ -452,33 +458,35 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
if (fragment instanceof AlbumsFragment) { if (fragment instanceof AlbumsFragment) {
sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z) sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z)
.setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_A_Z)); .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_A_Z));
sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a) sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a)
.setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_Z_A)); .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_Z_A));
sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist) sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist)
.setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_ARTIST)); .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_ARTIST));
sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year) sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year)
.setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_YEAR)); .setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_YEAR));
sortOrderMenu.add(0, R.id.action_album_sort_num_songs, 4, R.string.sort_num_songs)
.setChecked(currentSortOrder.equals(AlbumSortOrder.ALBUM_NUMBER_OF_SONGS));
} else if (fragment instanceof ArtistsFragment) { } else if (fragment instanceof ArtistsFragment) {
sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z) sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z)
.setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_A_Z)); .setChecked(currentSortOrder.equals(ArtistSortOrder.ARTIST_A_Z));
sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a) sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a)
.setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_Z_A)); .setChecked(currentSortOrder.equals(ArtistSortOrder.ARTIST_Z_A));
} else if (fragment instanceof SongsFragment) { } else if (fragment instanceof SongsFragment) {
sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z) sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_A_Z)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_A_Z));
sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a) sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_Z_A)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_Z_A));
sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist) sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ARTIST)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_ARTIST));
sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album) sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ALBUM)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_ALBUM));
sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year) sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_YEAR)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_YEAR));
sortOrderMenu.add(0, R.id.action_song_sort_order_date, 5, R.string.sort_order_date) sortOrderMenu.add(0, R.id.action_song_sort_order_date, 5, R.string.sort_order_date)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_DATE)); .setChecked(currentSortOrder.equals(SongSortOrder.SONG_DATE));
sortOrderMenu.add(0, R.id.action_song_sort_order_composer, 6, R.string.sort_order_composer) sortOrderMenu.add(0, R.id.action_song_sort_order_composer, 6, R.string.sort_order_composer)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.COMPOSER)); .setChecked(currentSortOrder.equals(SongSortOrder.COMPOSER));
} }
sortOrderMenu.setGroupCheckable(0, true, true); sortOrderMenu.setGroupCheckable(0, true, true);

View file

@ -63,7 +63,7 @@ class PlaylistsFragment : AbsLibraryPagerRecyclerViewFragment<PlaylistAdapter, L
adapter?.swapDataSet(ArrayList()) adapter?.swapDataSet(ArrayList())
} }
override fun playlists(playlists: ArrayList<Playlist>) { override fun playlists(playlists: List<Playlist>) {
adapter?.swapDataSet(playlists) adapter?.swapDataSet(playlists)
} }

View file

@ -40,7 +40,7 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
} }
override fun createAdapter(): SongAdapter { override fun createAdapter(): SongAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
return ShuffleButtonSongAdapter( return ShuffleButtonSongAdapter(
libraryFragment.mainActivity, libraryFragment.mainActivity,
dataSet, dataSet,
@ -49,7 +49,7 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
) )
} }
override fun songs(songs: ArrayList<Song>) { override fun songs(songs: List<Song>) {
adapter?.swapDataSet(songs) adapter?.swapDataSet(songs)
} }
@ -73,17 +73,6 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
PreferenceUtil.getInstance(requireContext()).setSongGridSizeLand(gridColumns) PreferenceUtil.getInstance(requireContext()).setSongGridSizeLand(gridColumns)
} }
public override fun saveUsePalette(usePalette: Boolean) {
PreferenceUtil.getInstance(requireContext()).setSongColoredFooters(usePalette)
}
public override fun loadUsePalette(): Boolean {
return PreferenceUtil.getInstance(requireContext()).songColoredFooters()
}
public override fun setUsePalette(usePalette: Boolean) {
}
override fun setGridSize(gridSize: Int) { override fun setGridSize(gridSize: Int) {
adapter?.notifyDataSetChanged() adapter?.notifyDataSetChanged()
} }

View file

@ -99,7 +99,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
private fun updateBlur() { private fun updateBlur() {
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext()) val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25) .getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
colorBackground!!.clearColorFilter() colorBackground?.clearColorFilter()
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong) SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext()) .checkIgnoreMediaStore(requireContext())
.generatePalette(requireContext()).build() .generatePalette(requireContext()).build()
@ -109,7 +109,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
.into(object : RetroMusicColoredTarget(colorBackground) { .into(object : RetroMusicColoredTarget(colorBackground) {
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
if (color == defaultFooterColor) { if (color == defaultFooterColor) {
colorBackground!!.setColorFilter(color) colorBackground?.setColorFilter(color)
} }
} }
}) })

View file

@ -13,9 +13,9 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.BlurTransformation import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget 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.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -53,7 +53,7 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
override fun onColorChanged(color: Int) { override fun onColorChanged(color: Int) {
playbackControlsFragment.setDark(color) playbackControlsFragment.setDark(color)
lastColor = color lastColor = color
callbacks!!.onPaletteColorChanged() callbacks?.onPaletteColorChanged()
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity) ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
playerToolbar.setTitleTextColor(Color.WHITE) playerToolbar.setTitleTextColor(Color.WHITE)
@ -127,10 +127,19 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
} }
private fun updateBlur() { private fun updateBlur() {
colorBackground?.clearColorFilter()
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext()) val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25) .getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
colorBackground!!.clearColorFilter() AlbumGlideRequest.Builder.from(Glide.with(requireContext()), MusicPlayerRemote.currentSong.albumId)
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong) .generatePalette(requireContext())
.build()
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
.into(object : RetroMusicColoredTarget(colorBackground) {
override fun onColorReady(color: Int) {
}
})
//colorBackground?.clearColorFilter()
/*SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext()) .checkIgnoreMediaStore(requireContext())
.generatePalette(requireContext()).build() .generatePalette(requireContext()).build()
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build()) .transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
@ -138,11 +147,9 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
//.override(320, 480) //.override(320, 480)
.into(object : RetroMusicColoredTarget(colorBackground) { .into(object : RetroMusicColoredTarget(colorBackground) {
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
if (color == defaultFooterColor) {
colorBackground!!.setColorFilter(color)
}
} }
}) })*/
} }
override fun onResume() { override fun onResume() {

View file

@ -18,8 +18,8 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.views.DrawableGradient import code.name.monkey.retromusic.views.DrawableGradient
import kotlinx.android.synthetic.main.fragment_player.* import kotlinx.android.synthetic.main.fragment_player.colorGradientBackground
import kotlinx.android.synthetic.main.fragment_player.playerToolbar
class PlayerFragment : AbsPlayerFragment() { class PlayerFragment : AbsPlayerFragment() {
@ -30,18 +30,21 @@ class PlayerFragment : AbsPlayerFragment() {
private lateinit var playbackControlsFragment: PlayerPlaybackControlsFragment private lateinit var playbackControlsFragment: PlayerPlaybackControlsFragment
private var valueAnimator: ValueAnimator? = null private var valueAnimator: ValueAnimator? = null
private fun colorize(i: Int) { private fun colorize(i: Int) {
if (valueAnimator != null) { if (valueAnimator != null) {
valueAnimator?.cancel() valueAnimator?.cancel()
} }
valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), ATHUtil.resolveColor(requireContext(), R.attr.colorSurface), i) valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), lastColor, i)
valueAnimator?.addUpdateListener { animation -> valueAnimator?.addUpdateListener { animation ->
if (isAdded) { if (isAdded) {
val drawable = DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM, val drawable = DrawableGradient(
intArrayOf(animation.animatedValue as Int, GradientDrawable.Orientation.TOP_BOTTOM,
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)), 0) intArrayOf(
animation.animatedValue as Int,
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)
), 0
)
colorGradientBackground?.background = drawable colorGradientBackground?.background = drawable
} }
} }
@ -70,7 +73,11 @@ class PlayerFragment : AbsPlayerFragment() {
lastColor = color lastColor = color
callbacks?.onPaletteColorChanged() callbacks?.onPaletteColorChanged()
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.colorControlNormal), requireActivity()) ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
ATHUtil.resolveColor(context, R.attr.colorControlNormal),
requireActivity()
)
if (PreferenceUtil.getInstance(requireContext()).adaptiveColor) { if (PreferenceUtil.getInstance(requireContext()).adaptiveColor) {
colorize(color) colorize(color)
@ -88,9 +95,10 @@ class PlayerFragment : AbsPlayerFragment() {
toggleFavorite(MusicPlayerRemote.currentSong) toggleFavorite(MusicPlayerRemote.currentSong)
} }
override fun onCreateView(
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_player, container, false) return inflater.inflate(R.layout.fragment_player, container, false)
} }
@ -101,19 +109,24 @@ class PlayerFragment : AbsPlayerFragment() {
setUpPlayerToolbar() setUpPlayerToolbar()
} }
private fun setUpSubFragments() { private fun setUpSubFragments() {
playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment playbackControlsFragment =
val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
val playerAlbumCoverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playerAlbumCoverFragment.setCallbacks(this) playerAlbumCoverFragment.setCallbacks(this)
} }
private fun setUpPlayerToolbar() { private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player) playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener {requireActivity().onBackPressed() } playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
playerToolbar.setOnMenuItemClickListener(this) playerToolbar.setOnMenuItemClickListener(this)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.colorControlNormal), requireActivity()) ToolbarContentTintHelper.colorizeToolbar(
playerToolbar,
ATHUtil.resolveColor(context, R.attr.colorControlNormal),
requireActivity()
)
} }
override fun onServiceConnected() { override fun onServiceConnected() {

View file

@ -0,0 +1,75 @@
/*
* 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) {
companion object {
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

@ -20,11 +20,9 @@ import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.RetroColorUtil
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.animation.GlideAnimation
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) { abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
protected val defaultFooterColor: Int protected val defaultFooterColor: Int
@ -40,15 +38,17 @@ abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(vi
onColorReady(defaultFooterColor) onColorReady(defaultFooterColor)
} }
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) { override fun onResourceReady(
resource: BitmapPaletteWrapper?,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
) {
super.onResourceReady(resource, glideAnimation) super.onResourceReady(resource, glideAnimation)
val defaultColor = defaultFooterColor val defaultColor = defaultFooterColor
resource?.let { resource?.let {
onColorReady(if (PreferenceUtil.getInstance(getView().context).isDominantColor) onColorReady(
RetroColorUtil.getDominantColor(it.bitmap, defaultColor) RetroColorUtil.getColor(it.palette, defaultColor)
else )
RetroColorUtil.getColor(it.palette, defaultColor))
} }
} }
} }

View file

@ -18,7 +18,9 @@ import android.graphics.Bitmap;
import androidx.palette.graphics.Palette; import androidx.palette.graphics.Palette;
public class BitmapPaletteWrapper { public class BitmapPaletteWrapper {
private final Bitmap mBitmap; private final Bitmap mBitmap;
private final Palette mPalette; private final Palette mPalette;
public BitmapPaletteWrapper(Bitmap bitmap, Palette palette) { public BitmapPaletteWrapper(Bitmap bitmap, Palette palette) {

View file

@ -29,7 +29,6 @@ import android.os.Environment
import android.os.IBinder import android.os.IBinder
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import code.name.monkey.retromusic.loaders.SongLoader import code.name.monkey.retromusic.loaders.SongLoader
@ -158,7 +157,7 @@ object MusicPlayerRemote {
return cursor.getString(columnIndex) return cursor.getString(columnIndex)
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, e.message) println(e.message)
} finally { } finally {
cursor?.close() cursor?.close()
} }
@ -222,7 +221,7 @@ object MusicPlayerRemote {
/** /**
* Async * Async
*/ */
fun openQueue(queue: ArrayList<Song>, startPosition: Int, startPlaying: Boolean) { fun openQueue(queue: List<Song>, startPosition: Int, startPlaying: Boolean) {
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) { if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
musicService!!.openQueue(queue, startPosition, startPlaying) musicService!!.openQueue(queue, startPosition, startPlaying)
if (PreferenceUtil.getInstance(musicService).isShuffleModeOn) if (PreferenceUtil.getInstance(musicService).isShuffleModeOn)
@ -233,7 +232,7 @@ object MusicPlayerRemote {
/** /**
* Async * Async
*/ */
fun openAndShuffleQueue(queue: ArrayList<Song>, startPlaying: Boolean) { fun openAndShuffleQueue(queue: List<Song>, startPlaying: Boolean) {
var startPosition = 0 var startPosition = 0
if (queue.isNotEmpty()) { if (queue.isNotEmpty()) {
startPosition = Random().nextInt(queue.size) startPosition = Random().nextInt(queue.size)
@ -246,7 +245,7 @@ object MusicPlayerRemote {
} }
private fun tryToHandleOpenPlayingQueue( private fun tryToHandleOpenPlayingQueue(
queue: ArrayList<Song>, queue: List<Song>,
startPosition: Int, startPosition: Int,
startPlaying: Boolean startPlaying: Boolean
): Boolean { ): Boolean {
@ -316,7 +315,7 @@ object MusicPlayerRemote {
return false return false
} }
fun playNext(songs: ArrayList<Song>): Boolean { fun playNext(songs: List<Song>): Boolean {
if (musicService != null) { if (musicService != null) {
if (playingQueue.size > 0) { if (playingQueue.size > 0) {
musicService!!.addSongs(position + 1, songs) musicService!!.addSongs(position + 1, songs)
@ -353,7 +352,7 @@ object MusicPlayerRemote {
return false return false
} }
fun enqueue(songs: ArrayList<Song>): Boolean { fun enqueue(songs: List<Song>): Boolean {
if (musicService != null) { if (musicService != null) {
if (playingQueue.size > 0) { if (playingQueue.size > 0) {
musicService!!.addSongs(songs) musicService!!.addSongs(songs)

View file

@ -21,6 +21,7 @@ class SortOrder {
* Artist sort order entries. * Artist sort order entries.
*/ */
interface ArtistSortOrder { interface ArtistSortOrder {
companion object { companion object {
/* Artist sort order A-Z */ /* Artist sort order A-Z */
@ -41,6 +42,7 @@ class SortOrder {
* Album sort order entries. * Album sort order entries.
*/ */
interface AlbumSortOrder { interface AlbumSortOrder {
companion object { companion object {
/* Album sort order A-Z */ /* Album sort order A-Z */
@ -57,7 +59,7 @@ class SortOrder {
+ ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER) + ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER)
/* Album sort order year */ /* Album sort order year */
const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" const val ALBUM_YEAR = MediaStore.Audio.Albums.FIRST_YEAR + " DESC"
} }
} }
@ -65,6 +67,7 @@ class SortOrder {
* Song sort order entries. * Song sort order entries.
*/ */
interface SongSortOrder { interface SongSortOrder {
companion object { companion object {
/* Song sort order A-Z */ /* Song sort order A-Z */
@ -97,6 +100,7 @@ class SortOrder {
* Album song sort order entries. * Album song sort order entries.
*/ */
interface AlbumSongSortOrder { interface AlbumSongSortOrder {
companion object { companion object {
/* Album song sort order A-Z */ /* Album song sort order A-Z */
@ -118,6 +122,7 @@ class SortOrder {
* Artist song sort order entries. * Artist song sort order entries.
*/ */
interface ArtistSongSortOrder { interface ArtistSongSortOrder {
companion object { companion object {
/* Artist song sort order A-Z */ /* Artist song sort order A-Z */
@ -144,6 +149,7 @@ class SortOrder {
* Artist album sort order entries. * Artist album sort order entries.
*/ */
interface ArtistAlbumSortOrder { interface ArtistAlbumSortOrder {
companion object { companion object {
/* Artist album sort order A-Z */ /* Artist album sort order A-Z */
@ -164,6 +170,7 @@ class SortOrder {
* Genre sort order entries. * Genre sort order entries.
*/ */
interface GenreSortOrder { interface GenreSortOrder {
companion object { companion object {
/* Genre sort order A-Z */ /* Genre sort order A-Z */
@ -173,5 +180,4 @@ class SortOrder {
const val ALBUM_Z_A = "$GENRE_A_Z DESC" const val ALBUM_Z_A = "$GENRE_A_Z DESC"
} }
} }
} }

View file

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

View file

@ -15,89 +15,136 @@
package code.name.monkey.retromusic.loaders package code.name.monkey.retromusic.loaders
import android.content.Context import android.content.Context
import android.provider.MediaStore.Audio.AudioColumns import android.database.Cursor
import android.provider.BaseColumns
import android.provider.MediaStore
import android.provider.MediaStore.Audio.Albums.*
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.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import java.util.* import android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI as SONGS_URI
import kotlin.collections.ArrayList
/** /**
* Created by hemanths on 11/08/17. * Created by hemanths on 11/08/17.
*/ */
object AlbumLoader { object AlbumLoader {
fun getAlbums( fun getAllAlbums(context: Context): List<Album> {
context: Context, return makeAlbumCursor(context, null, null)
query: String .mapList(true) {
): ArrayList<Album> { Album.fromCursor(this)
val songs = SongLoader.getSongs(SongLoader.makeSongCursor( }
context, }
AudioColumns.ALBUM + " LIKE ?",
arrayOf("%$query%"), fun getAlbum(context: Context, id: Long): Album {
getSongLoaderSortOrder(context)) return getAlbum(makeAlbumCursor(context, "_id=?", arrayOf(id.toString())))
}
fun getSongsForAlbum(context: Context, albumId: Long): ArrayList<Song> {
return SongLoader.getSongs(makeAlbumSongCursor(context, albumId))
}
fun getAlbumsForArtist(context: Context, artistId: Long): List<Album> {
return makeAlbumForArtistCursor(context, artistId).mapList(true) {
Album.fromCursor(this, artistId)
}
}
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(
getAlbumId(),
"album",
"artist",
"numsongs",
"minyear"
),
null,
null,
DEFAULT_SORT_ORDER
) )
return splitIntoAlbums(songs)
} }
fun getAlbum( private fun getAlbum(cursor: Cursor?): Album {
context: Context, return cursor?.use {
albumId: Int if (cursor.moveToFirst()) {
): Album { Album.fromCursor(cursor)
val songs = SongLoader.getSongs( } else {
SongLoader.makeSongCursor( null
context, }
AudioColumns.ALBUM_ID + "=?", } ?: Album()
arrayOf(albumId.toString()),
getSongLoaderSortOrder(context)))
val album = Album(songs)
sortSongsByTrackNumber(album)
return album
} }
fun getAllAlbums( private fun makeAlbumCursor(context: Context, selection: String?, paramArrayOfString: Array<String>?): Cursor? {
context: Context return context.contentResolver.query(
): ArrayList<Album> { EXTERNAL_CONTENT_URI,
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, null, null, getSongLoaderSortOrder(context))) arrayOf(
return splitIntoAlbums(songs) getAlbumId(),
"album", "artist",
"artist_id",
"numsongs",
"minyear"
),
selection,
paramArrayOfString,
PreferenceUtil.getInstance(context).albumSortOrder
)
}
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,
PreferenceUtil.getInstance(context).albumDetailSongSortOrder
)
} }
fun splitIntoAlbums( fun splitIntoAlbums(
songs: ArrayList<Song>? songs: ArrayList<Song>?
): ArrayList<Album> { ): ArrayList<Album> {
val albums = ArrayList<Album>() val albums = ArrayList<Album>()
if (songs != null) { if (songs != null) {
for (song in songs) { for (song in songs) {
getOrCreateAlbum(albums, song.albumId).songs?.add(song) getOrCreateAlbum(albums, song)
} }
} }
for (album in albums) {
sortSongsByTrackNumber(album)
}
return albums return albums
} }
private fun getOrCreateAlbum( private fun getOrCreateAlbum(
albums: ArrayList<Album>, albums: ArrayList<Album>,
albumId: Int song: Song
): Album { ): Album {
for (album in albums) { for (album in albums) {
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) { if (album.id == song.albumId) {
return album return album
} }
} }
val album = Album() val album = Album.fromSong(song)
albums.add(album) albums.add(album)
return album return album
} }
private fun sortSongsByTrackNumber(album: Album) { fun getAlbums(context: Context, paramString: String): List<Album> {
album.songs?.sortWith(Comparator { o1, o2 -> o1.trackNumber.compareTo(o2.trackNumber) }) return makeAlbumCursor(context, "album LIKE ?", arrayOf("$paramString%"))
} .mapList(true) { Album.fromCursor(this) }
private fun getSongLoaderSortOrder(context: Context): String {
return PreferenceUtil.getInstance(context).albumSortOrder + ", " + PreferenceUtil.getInstance(context).albumSongSortOrder
} }
} }
/*
* Android Q and more don't have `_id` for Albums and Artist albums so we have to use album_id
* */
fun getAlbumId(): String {
return if (VersionUtils.hasQ()) ALBUM_ID else BaseColumns._ID
}

View file

@ -15,64 +15,107 @@
package code.name.monkey.retromusic.loaders package code.name.monkey.retromusic.loaders
import android.content.Context import android.content.Context
import android.provider.MediaStore.Audio.AudioColumns 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.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
object ArtistLoader { object ArtistLoader {
private fun getSongLoaderSortOrder(context: Context): String {
return PreferenceUtil.getInstance(context).artistSortOrder + ", " + PreferenceUtil.getInstance(context).artistAlbumSortOrder + ", " + PreferenceUtil.getInstance(context).albumSongSortOrder
}
fun getAllArtists(context: Context): ArrayList<Artist> { fun getAllArtists(context: Context): ArrayList<Artist> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor( return getArtists(makeArtistCursor(context, null, null))
context,
null, null,
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
} }
fun getArtists(context: Context, query: String): ArrayList<Artist> { fun getArtist(context: Context, artistId: Long): Artist {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor( return getArtist(makeArtistCursor(context, "_id=?", arrayOf(artistId.toString())))
context,
AudioColumns.ARTIST + " LIKE ?",
arrayOf("%$query%"),
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
} }
fun splitIntoArtists(albums: ArrayList<Album>?): ArrayList<Artist> { private fun getArtist(cursor: Cursor?): Artist {
return cursor?.use {
if (cursor.moveToFirst()) {
Artist.fromCursor(cursor)
} else {
null
}
} ?: Artist()
}
fun getArtists(context: Context, paramString: String): List<Artist> {
return makeArtistCursor(context, "artist LIKE ?", arrayOf("$paramString%"))
.mapList(true) {
Artist.fromCursor(this)
}
}
private fun getArtists(cursor: Cursor?): ArrayList<Artist> {
val artists = ArrayList<Artist>() val artists = ArrayList<Artist>()
if (albums != null) { 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,
PreferenceUtil.getInstance(context).artistSortOrder
)
}
fun getSongsForArtist(context: Context, artistId: Long): List<Song> {
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
)
}
fun splitIntoArtists(albums: ArrayList<Album>): ArrayList<Artist> {
val artists = ArrayList<Artist>()
if (albums.isNotEmpty()) {
for (album in albums) { for (album in albums) {
getOrCreateArtist(artists, album.artistId).albums!!.add(album) getOrCreateArtist(artists, album)
} }
} }
return artists return artists
} }
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist { private fun getOrCreateArtist(artists: ArrayList<Artist>, album: Album): Artist {
for (artist in artists) { for (artist in artists) {
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) { if (artist.id == album.artistId) {
return artist return artist
} }
} }
val album = Artist() val a = Artist.fromAlbum(album)
artists.add(album) artists.add(a)
return album return a
}
fun getArtist(context: Context, artistId: Int): Artist {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
AudioColumns.ARTIST_ID + "=?",
arrayOf(artistId.toString()),
getSongLoaderSortOrder(context))
)
return Artist(AlbumLoader.splitIntoAlbums(songs))
} }
} }

View file

@ -19,7 +19,7 @@ import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.BaseColumns import android.provider.BaseColumns
import android.provider.MediaStore.Audio.Genres import android.provider.MediaStore.Audio.Genres
import code.name.monkey.retromusic.Constants.BASE_SELECTION import code.name.monkey.retromusic.Constants.baseSelection
import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
@ -94,7 +94,7 @@ object GenreLoader {
try { try {
return context.contentResolver.query( return context.contentResolver.query(
Genres.Members.getContentUri("external", genreId.toLong()), Genres.Members.getContentUri("external", genreId.toLong()),
baseProjection, BASE_SELECTION, null, PreferenceUtil.getInstance(context).songSortOrder) baseProjection, baseSelection, null, PreferenceUtil.getInstance(context).songSortOrder)
} catch (e: SecurityException) { } catch (e: SecurityException) {
return null return null
} }

View file

@ -36,10 +36,11 @@ object LastAddedSongsLoader {
val cutoff = PreferenceUtil.getInstance(context).lastAddedCutoff val cutoff = PreferenceUtil.getInstance(context).lastAddedCutoff
return SongLoader.makeSongCursor( return SongLoader.makeSongCursor(
context, context,
MediaStore.Audio.Media.DATE_ADDED + ">?", MediaStore.Audio.Media.DATE_ADDED + ">?",
arrayOf(cutoff.toString()), arrayOf(cutoff.toString()),
MediaStore.Audio.Media.DATE_ADDED + " DESC") MediaStore.Audio.Media.DATE_ADDED + " DESC"
)
} }
fun getLastAddedAlbums(context: Context): ArrayList<Album> { fun getLastAddedAlbums(context: Context): ArrayList<Album> {

View file

@ -18,7 +18,7 @@ import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio.AudioColumns
import code.name.monkey.retromusic.Constants.BASE_SELECTION import code.name.monkey.retromusic.Constants.baseSelection
import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.AbsCustomPlaylist
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.PlaylistSong
@ -104,7 +104,7 @@ object PlaylistSongsLoader {
MediaStore.Audio.Playlists.Members._ID,//11 MediaStore.Audio.Playlists.Members._ID,//11
AudioColumns.COMPOSER AudioColumns.COMPOSER
)// 12 )// 12
, BASE_SELECTION, null, , baseSelection, null,
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
) )
} catch (e: SecurityException) { } catch (e: SecurityException) {

View file

@ -18,10 +18,9 @@ import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio.AudioColumns
import code.name.monkey.retromusic.Constants.BASE_SELECTION
import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.Constants.baseSelection
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import java.util.ArrayList import java.util.ArrayList
@ -61,7 +60,7 @@ object SongLoader {
return getSongs(cursor) return getSongs(cursor)
} }
fun getSong( private fun getSong(
cursor: Cursor? cursor: Cursor?
): Song { ): Song {
val song: Song val song: Song
@ -75,98 +74,79 @@ object SongLoader {
} }
@JvmStatic @JvmStatic
fun getSong(context: Context, queryId: Int): Song { fun getSong(context: Context, queryId: Long): Song {
val cursor = makeSongCursor(context, AudioColumns._ID + "=?", arrayOf(queryId.toString())) val cursor = makeSongCursor(context, AudioColumns._ID + "=?", arrayOf(queryId.toString()))
return getSong(cursor) return getSong(cursor)
} }
private fun getSongFromCursorImpl( private fun getSongFromCursorImpl(
cursor: Cursor cursor: Cursor
): Song { ): Song = Song.fromCursor(cursor)
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)
return Song(
id, title, trackNumber, year, duration, data, dateModified, albumId,
albumName ?: "", artistId, artistName, composer ?: ""
)
}
@JvmStatic
@JvmOverloads @JvmOverloads
fun makeSongCursor( fun makeSongCursor(
context: Context, context: Context,
selection: String?, selectionString: String?,
selectionValues: Array<String>?, selectionValuesArray: Array<String>?,
sortOrder: String = PreferenceUtil.getInstance(context).songSortOrder sortOrder: String = PreferenceUtil.getInstance(context).songSortOrder
): Cursor? { ): Cursor {
var selectionFinal = selection var selectionValues: Array<String>? = arrayOf()
var selectionValuesFinal = selectionValues var selection = if (selectionString != null && selectionString.trim() != "") {
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") { "$baseSelection AND $selectionString"
"$BASE_SELECTION AND $selectionFinal"
} else { } else {
BASE_SELECTION baseSelection
} }
// Blacklist // Blacklist
val paths = BlacklistStore.getInstance(context).paths /*val paths = BlacklistStore.getInstance(context).paths
if (paths.isNotEmpty()) { if (paths.isNotEmpty()) {
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size) selection = generateBlacklistSelection(selection, paths.size)
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths) selectionValues = addBlacklistSelectionValues(selectionValuesArray, paths)
}*/
if (PreferenceUtil.getInstance(context).filterLength != 0) {
selection =
"$selection AND ${MediaStore.Audio.Media.DURATION} >= ${PreferenceUtil.getInstance(context).filterLength * 1000}"
} }
try { return context.contentResolver.query(
return context.contentResolver.query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, baseProjection,
baseProjection, selection,
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.getInstance( selectionValuesArray,
context sortOrder
).filterLength * 1000), )
selectionValuesFinal, ?: throw IllegalStateException("Unable to query ${MediaStore.Audio.Media.EXTERNAL_CONTENT_URI}, system returned null.")
sortOrder
)
} catch (e: SecurityException) {
return null
}
}
private fun generateBlacklistSelection(
selection: String?,
pathCount: Int
): String {
val newSelection = StringBuilder(
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
for (i in 0 until pathCount - 1) {
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
}
return newSelection.toString()
}
private fun addBlacklistSelectionValues(
selectionValues: Array<String>?,
paths: ArrayList<String>
): Array<String>? {
var selectionValuesFinal = selectionValues
if (selectionValuesFinal == null) {
selectionValuesFinal = emptyArray()
}
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
"n = $it"
}
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
for (i in selectionValuesFinal.size until newSelectionValues.size) {
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
}
return newSelectionValues
} }
} }
fun generateBlacklistSelection(
selection: String?,
pathCount: Int
): String {
val newSelection = StringBuilder(
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
for (i in 0 until pathCount - 1) {
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
}
return newSelection.toString()
}
fun addBlacklistSelectionValues(
selectionValues: Array<String>?,
paths: ArrayList<String>
): Array<String>? {
var selectionValuesFinal = selectionValues
if (selectionValuesFinal == null) {
selectionValuesFinal = emptyArray()
}
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
"n = $it"
}
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
for (i in selectionValuesFinal.size until newSelectionValues.size) {
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
}
return newSelectionValues
}

View file

@ -143,6 +143,6 @@ object TopAndRecentlyPlayedTracksLoader {
} }
fun getTopArtists(context: Context): ArrayList<Artist> { fun getTopArtists(context: Context): ArrayList<Artist> {
return ArtistLoader.splitIntoArtists(getTopAlbums(context)) return 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,72 @@
package code.name.monkey.retromusic.model package code.name.monkey.retromusic.model
import java.util.ArrayList import android.database.Cursor
import android.provider.MediaStore
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 code.name.monkey.retromusic.loaders.getAlbumId
class Album { data class Album(
val songs: ArrayList<Song>? 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 companion object {
get() = safeGetFirstSong().albumId fun fromCursor(cursor: Cursor, artistId: Long = -1): Album {
return Album(
id = cursor.value(getAlbumId()),
title = cursor.valueOrEmpty(ALBUM),
artist = cursor.valueOrEmpty(ARTIST),
artistId = if (artistId == -1L) cursor.value(MediaStore.Audio.AudioColumns.ARTIST_ID) else artistId,
songCount = cursor.value(NUMBER_OF_SONGS),
year = cursor.value(FIRST_YEAR)
)
}
val title: String? fun fromSong(song: Song): Album {
get() = safeGetFirstSong().albumName return Album(song.albumId, song.albumName, song.artistName, song.artistId, -1, song.year)
}
val artistId: Int }
get() = safeGetFirstSong().artistId }
val artistName: String? fun Cursor.valueOrEmpty(name: String): String = valueOrDefault(name, "")
get() = safeGetFirstSong().artistName
inline fun <reified T> Cursor.value(name: String): T {
val year: Int val index = getColumnIndexOrThrow(name)
get() = safeGetFirstSong().year return when (T::class) {
Short::class -> getShort(index) as T
val dateModified: Long Int::class -> getInt(index) as T
get() = safeGetFirstSong().dateModified Long::class -> getLong(index) as T
Boolean::class -> (getInt(index) == 1) as T
val songCount: Int String::class -> getString(index) as T
get() = songs!!.size Float::class -> getFloat(index) as T
Double::class -> getDouble(index) as T
constructor(songs: ArrayList<Song>) { ByteArray::class -> getBlob(index) as T
this.songs = songs else -> throw IllegalStateException("What do I do with ${T::class.java.simpleName}?")
} }
}
constructor() {
this.songs = ArrayList() inline fun <reified T> Cursor.valueOrDefault(name: String, defaultValue: T): T {
} val index = getColumnIndex(name)
if (index == -1) {
fun safeGetFirstSong(): Song { return defaultValue
return if (songs!!.isEmpty()) Song.emptySong else songs[0] }
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,57 +14,34 @@
package code.name.monkey.retromusic.model package code.name.monkey.retromusic.model
import code.name.monkey.retromusic.util.MusicUtil import android.database.Cursor
import java.util.ArrayList 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 { class Artist(
val albums: ArrayList<Album>? var id: Long = 0,
var name: String = "",
val id: Int var songCount: Int = 0,
get() = safeGetFirstAlbum().artistId var albumCount: Int = 0
) {
val name: String
get() {
val name = safeGetFirstAlbum().artistName
return if (MusicUtil.isArtistNameUnknown(name)) {
UNKNOWN_ARTIST_DISPLAY_NAME
} else name!!
}
val songCount: Int
get() {
var songCount = 0
for (album in albums!!) {
songCount += album.songCount
}
return songCount
}
val albumCount: Int
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()
}
fun safeGetFirstAlbum(): Album {
return if (albums!!.isEmpty()) Album() else albums[0]
}
companion object { 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)
)
}
fun fromAlbum(album: Album): Artist {
return Artist(album.artistId, album.artist, -1, -1)
}
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist" const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
} }
} }

View file

@ -13,21 +13,23 @@
*/ */
package code.name.monkey.retromusic.model package code.name.monkey.retromusic.model
import android.database.Cursor
import android.os.Parcelable import android.os.Parcelable
import android.provider.MediaStore.Audio.Media
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
open class Song( open class Song(
val id: Int, val id: Long,
val title: String, val title: String,
val trackNumber: Int, val trackNumber: Int,
val year: Int, val year: Int,
val duration: Long, val duration: Long,
val data: String, val data: String,
val dateModified: Long, val dateModified: Long,
val albumId: Int, val albumId: Long,
val albumName: String, val albumName: String,
val artistId: Int, val artistId: Long,
val artistName: String, val artistName: String,
val composer: String? val composer: String?
) : Parcelable { ) : Parcelable {
@ -49,5 +51,22 @@ open class Song(
"", "",
"" ""
) )
fun fromCursor(cursor: Cursor, albumId: Long = -1, artistId: Long = -1): Song {
return Song(
id = cursor.value(Media._ID),
albumId = cursor.valueOrDefault(Media.ALBUM_ID, albumId),
artistId = cursor.valueOrDefault(Media.ARTIST_ID, artistId),
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_MODIFIED),
duration = cursor.value(Media.DURATION),
title = cursor.valueOrEmpty(Media.TITLE),
trackNumber = cursor.value(Media.TRACK),
year = cursor.value(Media.YEAR)
)
}
} }
} }

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result.Success import code.name.monkey.retromusic.Result.Success
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist 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.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
@ -36,21 +37,24 @@ interface AlbumDetailsView {
fun album(album: Album) fun album(album: Album)
fun songs(songs: List<Song>)
fun complete() fun complete()
fun loadArtistImage(artist: Artist) fun loadArtistImage(artist: Artist)
fun moreAlbums( fun moreAlbums(albums: List<Album>)
albums: ArrayList<Album>
)
fun aboutAlbum(lastFmAlbum: LastFmAlbum) fun aboutAlbum(lastFmAlbum: LastFmAlbum)
} }
interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> { interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
fun loadAlbum(albumId: Int) fun loadAlbum(albumId: Long)
fun albumSongs(albumId: Long)
fun loadMore(artistId: Long)
fun loadMore(artistId: Int)
fun aboutAlbum(artist: String, album: String) fun aboutAlbum(artist: String, album: String)
class AlbumDetailsPresenterImpl @Inject constructor( class AlbumDetailsPresenterImpl @Inject constructor(
@ -60,7 +64,7 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private val job = Job() private val job = Job()
private lateinit var album: Album private lateinit var album: Album
override fun loadMore(artistId: Int) { override fun loadMore(artistId: Long) {
launch { launch {
when (val result = repository.artistById(artistId)) { when (val result = repository.artistById(artistId)) {
is Success -> withContext(Dispatchers.Main) { showArtistImage(result.data) } is Success -> withContext(Dispatchers.Main) { showArtistImage(result.data) }
@ -80,13 +84,9 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private fun showArtistImage(artist: Artist) { private fun showArtistImage(artist: Artist) {
view?.loadArtistImage(artist) view?.loadArtistImage(artist)
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 { launch {
when (val result = repository.albumById(albumId)) { when (val result = repository.albumById(albumId)) {
is Success -> withContext(Dispatchers.Main) { is Success -> withContext(Dispatchers.Main) {
@ -98,6 +98,15 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
} }
} }
override fun albumSongs(albumId: Long) {
launch {
when (val result = repository.albumSongsById(albumId)) {
is Success -> withContext(Dispatchers.Main) { view.songs(result.data) }
is Error -> withContext(Dispatchers.Main) {}
}
}
}
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
job.cancel() job.cancel()

View file

@ -25,7 +25,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.ArrayList
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -33,35 +32,37 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 12/08/17. * Created by hemanths on 12/08/17.
*/ */
interface AlbumsView : BaseView { interface AlbumsView : BaseView {
fun albums(albums: ArrayList<Album>)
fun albums(albums: List<Album>)
} }
interface AlbumsPresenter : Presenter<AlbumsView> { interface AlbumsPresenter : Presenter<AlbumsView> {
fun loadAlbums() fun loadAlbums()
class AlbumsPresenterImpl @Inject constructor( class AlbumsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<AlbumsView>(), AlbumsPresenter, CoroutineScope { ) : PresenterImpl<AlbumsView>(), AlbumsPresenter, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext private val job = Job()
get() = Dispatchers.IO + job
override fun detachView() { override val coroutineContext: CoroutineContext
super.detachView() get() = Dispatchers.IO + job
job.cancel()
}
override fun loadAlbums() { override fun detachView() {
launch { super.detachView()
when (val result = repository.allAlbums()) { job.cancel()
is Result.Success -> withContext(Dispatchers.Main) { }
view?.albums(result.data)
} override fun loadAlbums() {
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } 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,10 @@
package code.name.monkey.retromusic.mvp.presenter package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.Result.Success
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist 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.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
@ -35,14 +37,24 @@ import kotlin.coroutines.CoroutineContext
*/ */
interface ArtistDetailsView : BaseView { interface ArtistDetailsView : BaseView {
fun songs(songs: List<Song>)
fun albums(albums: List<Album>)
fun artist(artist: Artist) fun artist(artist: Artist)
fun artistInfo(lastFmArtist: LastFmArtist?) fun artistInfo(lastFmArtist: LastFmArtist?)
fun complete() fun complete()
} }
interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> { interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
fun loadArtist(artistId: Int) fun loadArtist(artistId: Long)
fun loadArtistSongs(artistId: Long)
fun loadArtistAlbums(artistId: Long)
fun loadBiography( fun loadBiography(
name: String, name: String,
@ -62,26 +74,35 @@ interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
override fun loadBiography(name: String, lang: String?, cache: String?) { override fun loadBiography(name: String, lang: String?, cache: String?) {
launch { launch {
when (val result = repository.artistInfo(name, lang, cache)) { when (val result = repository.artistInfo(name, lang, cache)) {
is Result.Success -> withContext(Dispatchers.Main) { is Success -> withContext(Dispatchers.Main) { view?.artistInfo(result.data) }
view?.artistInfo(result.data) is Error -> withContext(Dispatchers.Main) {}
}
is Result.Error -> withContext(Dispatchers.Main) {
}
} }
} }
} }
override fun loadArtist(artistId: Int) { override fun loadArtist(artistId: Long) {
launch { launch {
when (val result = repository.artistById(artistId)) { when (val result = repository.artistById(artistId)) {
is Result.Success -> withContext(Dispatchers.Main) { is Success -> withContext(Dispatchers.Main) { view?.artist(result.data) }
view?.artist(result.data) is Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
} override fun loadArtistSongs(artistId: Long) {
is Result.Error -> withContext(Dispatchers.Main) { launch {
view?.showEmptyView() when (val result = repository.artistSongsById(artistId)) {
} is Success -> withContext(Dispatchers.Main) { view.songs(result.data) }
is Error -> withContext(Dispatchers.Main) {}
}
}
}
override fun loadArtistAlbums(artistId: Long) {
launch {
when (val result = repository.artistAlbumsById(artistId)) {
is Success -> withContext(Dispatchers.Main) { view.albums(result.data) }
is Error -> withContext(Dispatchers.Main) {}
} }
} }
} }

View file

@ -20,12 +20,16 @@ import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
interface ArtistsView : BaseView { interface ArtistsView : BaseView {
fun artists(artists: ArrayList<Artist>) fun artists(artists: List<Artist>)
} }
interface ArtistsPresenter : Presenter<ArtistsView> { interface ArtistsPresenter : Presenter<ArtistsView> {
@ -33,8 +37,9 @@ interface ArtistsPresenter : Presenter<ArtistsView> {
fun loadArtists() fun loadArtists()
class ArtistsPresenterImpl @Inject constructor( class ArtistsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<ArtistsView>(), ArtistsPresenter, CoroutineScope { ) : PresenterImpl<ArtistsView>(), ArtistsPresenter, CoroutineScope {
private val job = Job() private val job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext

View file

@ -20,26 +20,30 @@ import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import java.util.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
/** /**
* Created by hemanths on 20/08/17. * Created by hemanths on 20/08/17.
*/ */
interface GenreDetailsView : BaseView { interface GenreDetailsView : BaseView {
fun songs(songs: ArrayList<Song>)
fun songs(songs: List<Song>)
} }
interface GenreDetailsPresenter : Presenter<GenreDetailsView> { interface GenreDetailsPresenter : Presenter<GenreDetailsView> {
fun loadGenreSongs(genreId: Int) fun loadGenreSongs(genreId: Int)
class GenreDetailsPresenterImpl @Inject constructor( class GenreDetailsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<GenreDetailsView>(), GenreDetailsPresenter, CoroutineScope { ) : PresenterImpl<GenreDetailsView>(), GenreDetailsPresenter, CoroutineScope {
private val job = Job() private val job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
@ -50,7 +54,6 @@ interface GenreDetailsPresenter : Presenter<GenreDetailsView> {
job.cancel() job.cancel()
} }
override fun loadGenreSongs(genreId: Int) { override fun loadGenreSongs(genreId: Int) {
launch { launch {
when (val result = repository.getGenre(genreId)) { when (val result = repository.getGenre(genreId)) {

View file

@ -20,8 +20,11 @@ import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import java.util.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -29,15 +32,17 @@ import kotlin.coroutines.CoroutineContext
* @author Hemanth S (h4h13). * @author Hemanth S (h4h13).
*/ */
interface GenresView : BaseView { interface GenresView : BaseView {
fun genres(genres: ArrayList<Genre>)
fun genres(genres: List<Genre>)
} }
interface GenresPresenter : Presenter<GenresView> { interface GenresPresenter : Presenter<GenresView> {
fun loadGenres() fun loadGenres()
class GenresPresenterImpl @Inject constructor( class GenresPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<GenresView>(), GenresPresenter, CoroutineScope { ) : PresenterImpl<GenresView>(), GenresPresenter, CoroutineScope {
private val job = Job() private val job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext

View file

@ -16,19 +16,25 @@ package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.mvp.* import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
/** /**
* Created by hemanths on 19/08/17. * Created by hemanths on 19/08/17.
*/ */
interface PlaylistView : BaseView { interface PlaylistView : BaseView {
fun playlists(playlists: ArrayList<Playlist>)
fun playlists(playlists: List<Playlist>)
} }
interface PlaylistsPresenter : Presenter<PlaylistView> { interface PlaylistsPresenter : Presenter<PlaylistView> {
@ -36,7 +42,7 @@ interface PlaylistsPresenter : Presenter<PlaylistView> {
fun playlists() fun playlists()
class PlaylistsPresenterImpl @Inject constructor( class PlaylistsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<PlaylistView>(), PlaylistsPresenter, CoroutineScope { ) : PresenterImpl<PlaylistView>(), PlaylistsPresenter, CoroutineScope {
private val job = Job() private val job = Job()

View file

@ -15,10 +15,17 @@
package code.name.monkey.retromusic.mvp.presenter package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.mvp.* 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
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -26,14 +33,15 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 20/08/17. * Created by hemanths on 20/08/17.
*/ */
interface PlaylistSongsView : BaseView { interface PlaylistSongsView : BaseView {
fun songs(songs: ArrayList<Song>)
fun songs(songs: List<Song>)
} }
interface PlaylistSongsPresenter : Presenter<PlaylistSongsView> { interface PlaylistSongsPresenter : Presenter<PlaylistSongsView> {
fun loadPlaylistSongs(playlist: Playlist) fun loadPlaylistSongs(playlist: Playlist)
class PlaylistSongsPresenterImpl @Inject constructor( class PlaylistSongsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<PlaylistSongsView>(), PlaylistSongsPresenter, CoroutineScope { ) : PresenterImpl<PlaylistSongsView>(), PlaylistSongsPresenter, CoroutineScope {
private var job: Job = Job() private var job: Job = Job()

View file

@ -16,10 +16,14 @@ package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.* import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import java.util.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -27,36 +31,37 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 10/08/17. * Created by hemanths on 10/08/17.
*/ */
interface SongView { interface SongView {
fun songs(songs: ArrayList<Song>)
fun showEmptyView() fun songs(songs: List<Song>)
fun showEmptyView()
} }
interface SongPresenter : Presenter<SongView> { interface SongPresenter : Presenter<SongView> {
fun loadSongs() fun loadSongs()
class SongPresenterImpl @Inject constructor( class SongPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<SongView>(), SongPresenter, CoroutineScope { ) : PresenterImpl<SongView>(), SongPresenter, CoroutineScope {
private var job: Job = Job() private var job: Job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job get() = Dispatchers.IO + job
override fun loadSongs() { override fun loadSongs() {
launch { launch {
when (val songs = repository.allSongs()) { when (val songs = repository.allSongs()) {
is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) } is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) }
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
} }
} }
} }
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
job.cancel(); job.cancel();
} }
} }
} }

View file

@ -41,7 +41,12 @@ class BlacklistPreference : ATEDialogPreference {
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
)
init { init {
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN) icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
@ -55,23 +60,23 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
} }
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val blacklistFolderChooserDialog = childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog? val blacklistFolderChooserDialog =
childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog?
blacklistFolderChooserDialog?.setCallback(this) blacklistFolderChooserDialog?.setCallback(this)
refreshBlacklistData() refreshBlacklistData()
return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show { return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(code.name.monkey.retromusic.R.string.blacklist) title(R.string.blacklist)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner) cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
positiveButton(android.R.string.ok) { positiveButton(android.R.string.ok) {
dismiss() dismiss()
} }
neutralButton(text = getString(R.string.clear_action)) { neutralButton(text = getString(R.string.clear_action)) {
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(code.name.monkey.retromusic.R.string.clear_blacklist) title(R.string.clear_blacklist)
message(code.name.monkey.retromusic.R.string.do_you_want_to_clear_the_blacklist) message(R.string.do_you_want_to_clear_the_blacklist)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner) cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
positiveButton(code.name.monkey.retromusic.R.string.clear_action) { positiveButton(R.string.clear_action) {
BlacklistStore.getInstance(context).clear() BlacklistStore.getInstance(context).clear()
refreshBlacklistData() refreshBlacklistData()
} }
@ -81,13 +86,20 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
negativeButton(R.string.add_action) { negativeButton(R.string.add_action) {
val dialog = BlacklistFolderChooserDialog.create() val dialog = BlacklistFolderChooserDialog.create()
dialog.setCallback(this@BlacklistPreferenceDialog) dialog.setCallback(this@BlacklistPreferenceDialog)
dialog.show(childFragmentManager, "FOLDER_CHOOSER"); dialog.show(childFragmentManager, "FOLDER_CHOOSER")
} }
listItems(items = paths, waitForPositiveButton = false) { _, _, text -> listItems(items = paths, waitForPositiveButton = false) { _, _, text ->
MaterialDialog(context, BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner) cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
title(code.name.monkey.retromusic.R.string.remove_from_blacklist) title(R.string.remove_from_blacklist)
message(text = Html.fromHtml(getString(code.name.monkey.retromusic.R.string.do_you_want_to_remove_from_the_blacklist, text))) message(
text = Html.fromHtml(
getString(
R.string.do_you_want_to_remove_from_the_blacklist,
text
)
)
)
positiveButton(code.name.monkey.retromusic.R.string.remove_action) { positiveButton(code.name.monkey.retromusic.R.string.remove_action) {
BlacklistStore.getInstance(context).removePath(File(text.toString())) BlacklistStore.getInstance(context).removePath(File(text.toString()))
refreshBlacklistData() refreshBlacklistData()
@ -108,7 +120,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
} }
override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) { override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) {
BlacklistStore.getInstance(context!!).addPath(folder); BlacklistStore.getInstance(context!!).addPath(folder)
refreshBlacklistData(); refreshBlacklistData()
} }
} }

View file

@ -16,6 +16,7 @@ package code.name.monkey.retromusic.preferences
import android.app.Dialog import android.app.Dialog
import android.content.Context import android.content.Context
import android.content.res.ColorStateList
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.util.AttributeSet import android.util.AttributeSet
@ -30,8 +31,12 @@ import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.App import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.NowPlayingScreen import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -42,18 +47,23 @@ import com.bumptech.glide.Glide
class NowPlayingScreenPreference : ATEDialogPreference { class NowPlayingScreenPreference : ATEDialogPreference {
constructor(context: Context) : super(context) {} constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {} constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
)
private val mLayoutRes = R.layout.preference_dialog_now_playing_screen private val mLayoutRes = R.layout.preference_dialog_now_playing_screen
override fun getDialogLayoutResource(): Int { override fun getDialogLayoutResource(): Int {
return mLayoutRes; return mLayoutRes
} }
init { init {
@ -66,11 +76,9 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
private var viewPagerPosition: Int = 0 private var viewPagerPosition: Int = 0
override fun onPageScrollStateChanged(state: Int) { override fun onPageScrollStateChanged(state: Int) {
} }
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
} }
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
@ -78,13 +86,12 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
} }
override fun onDialogClosed(positiveResult: Boolean) { override fun onDialogClosed(positiveResult: Boolean) {
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = LayoutInflater.from(activity).inflate(R.layout.preference_dialog_now_playing_screen, null) val view = LayoutInflater.from(activity).inflate(R.layout.preference_dialog_now_playing_screen, null)
val viewPager = view.findViewById<ViewPager>(R.id.now_playing_screen_view_pager) val viewPager = view.findViewById<ViewPager>(R.id.now_playing_screen_view_pager)
?: throw IllegalStateException("Dialog view must contain a ViewPager with id 'now_playing_screen_view_pager'") ?: throw IllegalStateException("Dialog view must contain a ViewPager with id 'now_playing_screen_view_pager'")
viewPager.adapter = NowPlayingScreenAdapter(activity!!) viewPager.adapter = NowPlayingScreenAdapter(activity!!)
viewPager.addOnPageChangeListener(this) viewPager.addOnPageChangeListener(this)
viewPager.pageMargin = ViewUtil.convertDpToPixel(32f, resources).toInt() viewPager.pageMargin = ViewUtil.convertDpToPixel(32f, resources).toInt()
@ -109,24 +116,6 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
} }
} }
private fun isNowPlayingThemes(nowPlayingScreen: NowPlayingScreen): Boolean {
if (nowPlayingScreen == NowPlayingScreen.BLUR_CARD) {
PreferenceUtil.getInstance(requireContext()).resetCarouselEffect()
PreferenceUtil.getInstance(requireContext()).resetCircularAlbumArt()
}
return (nowPlayingScreen == NowPlayingScreen.FULL ||
nowPlayingScreen == NowPlayingScreen.CARD ||
nowPlayingScreen == NowPlayingScreen.PLAIN ||
nowPlayingScreen == NowPlayingScreen.BLUR ||
nowPlayingScreen == NowPlayingScreen.COLOR ||
nowPlayingScreen == NowPlayingScreen.SIMPLE ||
nowPlayingScreen == NowPlayingScreen.BLUR_CARD ||
nowPlayingScreen == NowPlayingScreen.CIRCLE ||
nowPlayingScreen == NowPlayingScreen.ADAPTIVE)
&& !App.isProVersion()
}
companion object { companion object {
fun newInstance(key: String): NowPlayingScreenPreferenceDialog { fun newInstance(key: String): NowPlayingScreenPreferenceDialog {
val bundle = Bundle() val bundle = Bundle()
@ -138,7 +127,7 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
} }
} }
private class NowPlayingScreenAdapter internal constructor(private val context: Context) : PagerAdapter() { private class NowPlayingScreenAdapter(private val context: Context) : PagerAdapter() {
override fun instantiateItem(collection: ViewGroup, position: Int): Any { override fun instantiateItem(collection: ViewGroup, position: Int): Any {
val nowPlayingScreen = NowPlayingScreen.values()[position] val nowPlayingScreen = NowPlayingScreen.values()[position]
@ -148,16 +137,26 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
collection.addView(layout) collection.addView(layout)
val image = layout.findViewById<ImageView>(R.id.image) val image = layout.findViewById<ImageView>(R.id.image)
val proText = layout.findViewById<TextView>(R.id.proText)
val title = layout.findViewById<TextView>(R.id.title) val title = layout.findViewById<TextView>(R.id.title)
Glide.with(context).load(nowPlayingScreen.drawableResId).into(image) Glide.with(context).load(nowPlayingScreen.drawableResId).into(image)
title.setText(nowPlayingScreen.titleRes) title.setText(nowPlayingScreen.titleRes)
if (isNowPlayingThemes(nowPlayingScreen)) {
proText.show()
} else {
proText.hide()
}
val color = ThemeStore.accentColor(context)
proText.backgroundTintList = ColorStateList.valueOf(color)
proText.setTextColor(MaterialValueHelper.getPrimaryTextColor(context,ColorUtil.isColorLight(color)))
return layout return layout
} }
override fun destroyItem(collection: ViewGroup, override fun destroyItem(
position: Int, collection: ViewGroup,
view: Any) { position: Int,
view: Any
) {
collection.removeView(view as View) collection.removeView(view as View)
} }
@ -173,3 +172,18 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
return context.getString(NowPlayingScreen.values()[position].titleRes) return context.getString(NowPlayingScreen.values()[position].titleRes)
} }
} }
fun isNowPlayingThemes(nowPlayingScreen: NowPlayingScreen): Boolean {
return (nowPlayingScreen == NowPlayingScreen.FULL ||
nowPlayingScreen == NowPlayingScreen.CARD ||
nowPlayingScreen == NowPlayingScreen.PLAIN ||
nowPlayingScreen == NowPlayingScreen.BLUR ||
nowPlayingScreen == NowPlayingScreen.COLOR ||
nowPlayingScreen == NowPlayingScreen.SIMPLE ||
nowPlayingScreen == NowPlayingScreen.BLUR_CARD ||
nowPlayingScreen == NowPlayingScreen.CIRCLE ||
nowPlayingScreen == NowPlayingScreen.ADAPTIVE ||
nowPlayingScreen == NowPlayingScreen.MATERIAL ||
nowPlayingScreen == NowPlayingScreen.PEAK)
&& !App.isProVersion()
}

View file

@ -45,7 +45,7 @@ import javax.inject.Inject
class RepositoryImpl @Inject constructor(private val context: Context) : Repository { 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 { return try {
val albums = AlbumLoader.getAllAlbums(context) val albums = AlbumLoader.getAllAlbums(context)
if (albums.isNotEmpty()) { if (albums.isNotEmpty()) {
@ -58,14 +58,37 @@ 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 { return try {
val album = AlbumLoader.getAlbum(context, albumId) val album = AlbumLoader.getAlbum(context, albumId)
if (album != null) { Success(album)
Success(album) } catch (e: Exception) {
} else { Error(e)
Error(Throwable("No album")) }
} }
override suspend fun albumSongsById(albumId: Long): Result<List<Song>> {
return try {
val songs = AlbumLoader.getSongsForAlbum(context, albumId)
Success(songs)
} catch (e: Exception) {
Error(e)
}
}
override suspend fun artistSongsById(artistId: Long): Result<List<Song>> {
return try {
val songs = ArtistLoader.getSongsForArtist(context, artistId)
Success(songs)
} catch (e: Exception) {
Error(e)
}
}
override suspend fun artistAlbumsById(artistId: Long): Result<List<Album>> {
return try {
val albums = AlbumLoader.getAlbumsForArtist(context, artistId)
Success(albums)
} catch (e: Exception) { } catch (e: Exception) {
Error(e) Error(e)
} }
@ -289,7 +312,7 @@ class RepositoryImpl @Inject constructor(private val context: Context) : Reposit
errorMessage = "Error" errorMessage = "Error"
) )
override suspend fun artistById(artistId: Int): Result<Artist> { override suspend fun artistById(artistId: Long): Result<Artist> {
return try { return try {
val artist = ArtistLoader.getArtist(context, artistId) val artist = ArtistLoader.getArtist(context, artistId)
return Success(artist) return Success(artist)

View file

@ -30,23 +30,29 @@ import code.name.monkey.retromusic.rest.model.LastFmArtist
interface Repository { 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>> suspend fun albumSongsById(albumId: Long): Result<List<Song>>
suspend fun allArtists(): Result<ArrayList<Artist>> suspend fun artistSongsById(artistId: Long): Result<List<Song>>
suspend fun allPlaylists(): Result<ArrayList<Playlist>> suspend fun artistAlbumsById(artistId: Long): Result<List<Album>>
suspend fun allGenres(): Result<ArrayList<Genre>> suspend fun allSongs(): Result<List<Song>>
suspend fun allArtists(): Result<List<Artist>>
suspend fun allPlaylists(): Result<List<Playlist>>
suspend fun allGenres(): Result<List<Genre>>
suspend fun search(query: String?): Result<MutableList<Any>> suspend fun search(query: String?): Result<MutableList<Any>>
suspend fun getPlaylistSongs(playlist: Playlist): Result<ArrayList<Song>> suspend fun getPlaylistSongs(playlist: Playlist): Result<List<Song>>
suspend fun getGenre(genreId: Int): Result<ArrayList<Song>> suspend fun getGenre(genreId: Int): Result<List<Song>>
suspend fun recentArtists(): Result<Home> suspend fun recentArtists(): Result<Home>
@ -62,5 +68,5 @@ interface Repository {
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum> 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; break;
case SHUFFLE_MODE_NONE: case SHUFFLE_MODE_NONE:
this.shuffleMode = shuffleMode; this.shuffleMode = shuffleMode;
int currentSongId = Objects.requireNonNull(getCurrentSong()).getId(); long currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
playingQueue = new ArrayList<>(originalPlayingQueue); playingQueue = new ArrayList<>(originalPlayingQueue);
int newPosition = 0; int newPosition = 0;
if (getPlayingQueue() != null) { if (getPlayingQueue() != null) {
@ -844,7 +844,7 @@ public class MusicService extends Service implements
return true; return true;
} }
public void openQueue(@Nullable final ArrayList<Song> playingQueue, final int startPosition, public void openQueue(@Nullable final List<Song> playingQueue, final int startPosition,
final boolean startPlaying) { final boolean startPlaying) {
if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue
.size()) { .size()) {

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

@ -19,10 +19,11 @@ import android.database.Cursor;
import android.os.Environment; import android.os.Environment;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.loaders.SortedCursor;
import code.name.monkey.retromusic.model.Song;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -37,137 +38,9 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.loaders.SortedCursor;
import code.name.monkey.retromusic.model.Song;
public final class FileUtil { public final class FileUtil {
private FileUtil() {
}
public static byte[] readBytes(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int count;
while ((count = stream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
stream.close();
return baos.toByteArray();
}
@NonNull
public static ArrayList<Song> matchFilesWithMediaStore(@NonNull Context context,
@Nullable List<File> files) {
return SongLoader.INSTANCE.getSongs(makeSongCursor(context, files));
}
public static String safeGetCanonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsolutePath();
}
}
@Nullable
public static SortedCursor makeSongCursor(@NonNull final Context context,
@Nullable final List<File> files) {
String selection = null;
String[] paths = null;
if (files != null) {
paths = toPathArray(files);
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
}
Cursor songCursor = SongLoader.INSTANCE.makeSongCursor(context, selection, selection == null ? null : paths);
return songCursor == null ? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
}
private static String makePlaceholders(int len) {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
@Nullable
private static String[] toPathArray(@Nullable List<File> files) {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
/*try {
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
} catch (IOException e) {
e.printStackTrace();
paths[i] = files.get(i).getPath();
}*/
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
}
return null;
}
@NonNull
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> fileList = new LinkedList<>();
File[] found = directory.listFiles(fileFilter);
if (found != null) {
Collections.addAll(fileList, found);
}
return fileList;
}
@NonNull
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> files = new LinkedList<>();
internalListFilesDeep(files, directory, fileFilter);
return files;
}
@NonNull
public static List<File> listFilesDeep(@NonNull Collection<File> files,
@Nullable FileFilter fileFilter) {
List<File> resFiles = new LinkedList<>();
for (File file : files) {
if (file.isDirectory()) {
internalListFilesDeep(resFiles, file, fileFilter);
} else if (fileFilter == null || fileFilter.accept(file)) {
resFiles.add(file);
}
}
return resFiles;
}
private static void internalListFilesDeep(@NonNull Collection<File> files,
@NonNull File directory, @Nullable FileFilter fileFilter) {
File[] found = directory.listFiles(fileFilter);
if (found != null) {
for (File file : found) {
if (file.isDirectory()) {
internalListFilesDeep(files, file, fileFilter);
} else {
files.add(file);
}
}
}
}
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) { public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
if (mimeType == null || mimeType.equals("*/*")) { if (mimeType == null || mimeType.equals("*/*")) {
return true; return true;
@ -209,15 +82,95 @@ public final class FileUtil {
} }
} }
public static String stripExtension(String str) { public static boolean isExternalMemoryAvailable() {
if (str == null) { Boolean isSDPresent = Environment.getExternalStorageState()
return null; .equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if (isSDSupportedDevice && isSDPresent) {
// yes SD-card is present
return true;
} else {
return false;
// Sorry
} }
int pos = str.lastIndexOf('.'); }
if (pos == -1) {
return str; @NonNull
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> fileList = new LinkedList<>();
File[] found = directory.listFiles(fileFilter);
if (found != null) {
Collections.addAll(fileList, found);
} }
return str.substring(0, pos); return fileList;
}
@NonNull
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> files = new LinkedList<>();
internalListFilesDeep(files, directory, fileFilter);
return files;
}
@NonNull
public static List<File> listFilesDeep(@NonNull Collection<File> files,
@Nullable FileFilter fileFilter) {
List<File> resFiles = new LinkedList<>();
for (File file : files) {
if (file.isDirectory()) {
internalListFilesDeep(resFiles, file, fileFilter);
} else if (fileFilter == null || fileFilter.accept(file)) {
resFiles.add(file);
}
}
return resFiles;
}
@Nullable
public static SortedCursor makeSongCursor(@NonNull final Context context,
@Nullable final List<File> files) {
String selection = null;
String[] paths = null;
if (files != null) {
paths = toPathArray(files);
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
}
Cursor songCursor = SongLoader.makeSongCursor(context, selection, selection == null ? null : paths);
return songCursor == null ? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
}
@NonNull
public static ArrayList<Song> matchFilesWithMediaStore(@NonNull Context context,
@Nullable List<File> files) {
return SongLoader.INSTANCE.getSongs(makeSongCursor(context, files));
}
public static String read(File file) throws Exception {
FileInputStream fin = new FileInputStream(file);
String ret = readFromStream(fin);
fin.close();
return ret;
}
public static byte[] readBytes(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int count;
while ((count = stream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
stream.close();
return baos.toByteArray();
} }
public static String readFromStream(InputStream is) throws Exception { public static String readFromStream(InputStream is) throws Exception {
@ -234,27 +187,6 @@ public final class FileUtil {
return sb.toString(); return sb.toString();
} }
public static String read(File file) throws Exception {
FileInputStream fin = new FileInputStream(file);
String ret = readFromStream(fin);
fin.close();
return ret;
}
public static boolean isExternalMemoryAvailable() {
Boolean isSDPresent = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if (isSDSupportedDevice && isSDPresent) {
// yes SD-card is present
return true;
} else {
return false;
// Sorry
}
}
public static File safeGetCanonicalFile(File file) { public static File safeGetCanonicalFile(File file) {
try { try {
return file.getCanonicalFile(); return file.getCanonicalFile();
@ -264,5 +196,70 @@ public final class FileUtil {
} }
} }
public static String safeGetCanonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsolutePath();
}
}
public static String stripExtension(String str) {
if (str == null) {
return null;
}
int pos = str.lastIndexOf('.');
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
private FileUtil() {
}
private static void internalListFilesDeep(@NonNull Collection<File> files,
@NonNull File directory, @Nullable FileFilter fileFilter) {
File[] found = directory.listFiles(fileFilter);
if (found != null) {
for (File file : found) {
if (file.isDirectory()) {
internalListFilesDeep(files, file, fileFilter);
} else {
files.add(file);
}
}
}
}
private static String makePlaceholders(int len) {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
@Nullable
private static String[] toPathArray(@Nullable List<File> files) {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
/*try {
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
} catch (IOException e) {
e.printStackTrace();
paths[i] = files.get(i).getPath();
}*/
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
}
return null;
}
} }

View file

@ -99,7 +99,7 @@ public class MusicUtil {
} }
} }
public static void deleteAlbumArt(@NonNull Context context, int albumId) { public static void deleteAlbumArt(@NonNull Context context, long albumId) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
Uri localUri = Uri.parse("content://media/external/audio/albumart"); Uri localUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null); contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
@ -262,7 +262,7 @@ public class MusicUtil {
} }
@NonNull @NonNull
public static Uri getMediaStoreAlbumCoverUri(int albumId) { public static Uri getMediaStoreAlbumCoverUri(long albumId) {
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart"); final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
return ContentUris.withAppendedId(sArtworkUri, albumId); return ContentUris.withAppendedId(sArtworkUri, albumId);
} }
@ -322,7 +322,7 @@ public class MusicUtil {
return songCount + " " + songString; 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); return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
} }
@ -348,7 +348,7 @@ public class MusicUtil {
return -1; return -1;
} }
public static void insertAlbumArt(@NonNull Context context, int albumId, String path) { public static void insertAlbumArt(@NonNull Context context, long albumId, String path) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
Uri artworkUri = Uri.parse("content://media/external/audio/albumart"); Uri artworkUri = Uri.parse("content://media/external/audio/albumart");

View file

@ -59,14 +59,14 @@ public class NavigationUtil {
ActivityCompat.startActivity(activity, new Intent(activity, AboutActivity.class), null); ActivityCompat.startActivity(activity, new Intent(activity, AboutActivity.class), null);
} }
public static void goToAlbum(@NonNull Activity activity, int albumId) { public static void goToAlbum(@NonNull Activity activity, long albumId) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class); Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId); intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
ActivityCompat.startActivity(activity, intent, null); ActivityCompat.startActivity(activity, intent, null);
} }
public static void goToAlbumOptions(@NonNull Activity activity, public static void goToAlbumOptions(@NonNull Activity activity,
int albumId, long albumId,
@NonNull ActivityOptions options) { @NonNull ActivityOptions options) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class); Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId); intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
@ -80,7 +80,7 @@ public class NavigationUtil {
} }
public static void goToArtistOptions(@NotNull Activity activity, public static void goToArtistOptions(@NotNull Activity activity,
int artistId, long artistId,
@NonNull ActivityOptions options) { @NonNull ActivityOptions options) {
Intent intent = new Intent(activity, ArtistDetailActivity.class); 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, static boolean doPlaylistContains(@NonNull final Context context, final long playlistId,
final int songId) { final long songId) {
if (playlistId != -1) { if (playlistId != -1) {
try { try {
Cursor c = context.getContentResolver().query( Cursor c = context.getContentResolver().query(

View file

@ -14,6 +14,12 @@
package code.name.monkey.retromusic.util; package code.name.monkey.retromusic.util;
import static code.name.monkey.retromusic.helper.SortOrder.ArtistAlbumSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.ArtistSongSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.GenreSortOrder;
import static code.name.monkey.retromusic.helper.SortOrder.SongSortOrder;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -33,8 +39,8 @@ import code.name.monkey.retromusic.activities.MainActivity;
import code.name.monkey.retromusic.fragments.AlbumCoverStyle; import code.name.monkey.retromusic.fragments.AlbumCoverStyle;
import code.name.monkey.retromusic.fragments.NowPlayingScreen; import code.name.monkey.retromusic.fragments.NowPlayingScreen;
import code.name.monkey.retromusic.fragments.mainactivity.folders.FoldersFragment; import code.name.monkey.retromusic.fragments.mainactivity.folders.FoldersFragment;
import code.name.monkey.retromusic.helper.SortOrder;
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder; import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder;
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder;
import code.name.monkey.retromusic.model.CategoryInfo; import code.name.monkey.retromusic.model.CategoryInfo;
import code.name.monkey.retromusic.transform.CascadingPageTransformer; import code.name.monkey.retromusic.transform.CascadingPageTransformer;
import code.name.monkey.retromusic.transform.DepthTransformation; import code.name.monkey.retromusic.transform.DepthTransformation;
@ -365,6 +371,7 @@ public final class PreferenceUtil {
} }
} }
@NonNull
public String getAlbumDetailSongSortOrder() { public String getAlbumDetailSongSortOrder() {
return mPreferences return mPreferences
.getString(ALBUM_DETAIL_SONG_SORT_ORDER, AlbumSongSortOrder.SONG_TRACK_LIST); .getString(ALBUM_DETAIL_SONG_SORT_ORDER, AlbumSongSortOrder.SONG_TRACK_LIST);
@ -417,8 +424,9 @@ public final class PreferenceUtil {
.getString(ALBUM_SONG_SORT_ORDER, AlbumSongSortOrder.SONG_TRACK_LIST); .getString(ALBUM_SONG_SORT_ORDER, AlbumSongSortOrder.SONG_TRACK_LIST);
} }
@NonNull
public final String getAlbumSortOrder() { public final String getAlbumSortOrder() {
return mPreferences.getString(ALBUM_SORT_ORDER, SortOrder.AlbumSortOrder.ALBUM_A_Z); return mPreferences.getString(ALBUM_SORT_ORDER, AlbumSortOrder.ALBUM_A_Z);
} }
public void setAlbumSortOrder(final String sortOrder) { public void setAlbumSortOrder(final String sortOrder) {
@ -428,12 +436,12 @@ public final class PreferenceUtil {
} }
public final String getArtistAlbumSortOrder() { public final String getArtistAlbumSortOrder() {
return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR); return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER, ArtistAlbumSortOrder.ALBUM_YEAR);
} }
public String getArtistDetailSongSortOrder() { public String getArtistDetailSongSortOrder() {
return mPreferences return mPreferences
.getString(ARTIST_DETAIL_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); .getString(ARTIST_DETAIL_SONG_SORT_ORDER, ArtistSongSortOrder.SONG_A_Z);
} }
public void setArtistDetailSongSortOrder(String sortOrder) { public void setArtistDetailSongSortOrder(String sortOrder) {
@ -462,11 +470,12 @@ public final class PreferenceUtil {
} }
public final String getArtistSongSortOrder() { public final String getArtistSongSortOrder() {
return mPreferences.getString(ARTIST_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); return mPreferences.getString(ARTIST_SONG_SORT_ORDER, ArtistSongSortOrder.SONG_A_Z);
} }
@NonNull
public final String getArtistSortOrder() { public final String getArtistSortOrder() {
return mPreferences.getString(ARTIST_SORT_ORDER, SortOrder.ArtistSortOrder.ARTIST_A_Z); return mPreferences.getString(ARTIST_SORT_ORDER, ArtistSortOrder.ARTIST_A_Z);
} }
public void setArtistSortOrder(final String sortOrder) { public void setArtistSortOrder(final String sortOrder) {
@ -536,7 +545,7 @@ public final class PreferenceUtil {
} }
public final String getGenreSortOrder() { public final String getGenreSortOrder() {
return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z); return mPreferences.getString(GENRE_SORT_ORDER, GenreSortOrder.GENRE_A_Z);
} }
public boolean getHeadsetPlugged() { public boolean getHeadsetPlugged() {
@ -719,7 +728,7 @@ public final class PreferenceUtil {
} }
public final String getSongSortOrder() { public final String getSongSortOrder() {
return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.SONG_A_Z); return mPreferences.getString(SONG_SORT_ORDER, SongSortOrder.SONG_A_Z);
} }
public void setSongSortOrder(final String sortOrder) { public void setSongSortOrder(final String sortOrder) {

View file

@ -1,9 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<shape xmlns:android="http://schemas.android.com/apk/res/android" ~ Copyright (c) 2020 Hemanth Savarala.
android:shape="oval"> ~
<corners android:radius="35dp"/> ~ Licensed under the GNU General Public License v3
<stroke ~
android:color="@color/md_white_1000" ~ This is free software: you can redistribute it and/or modify it under
android:width="2dp"/> ~ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp" />
<stroke
android:width="2dp"
android:color="?attr/colorAccent" />
</shape> </shape>

View file

@ -2,9 +2,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/gradient_background" android:id="@+id/gradient_background"
android:background="?attr/colorSurface"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="?attr/colorSurface">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -87,6 +87,24 @@
android:maxLines="1" /> android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/artistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/artistText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="@string/artist"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/albumArtistContainer" android:id="@+id/albumArtistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer" android:id="@+id/imageContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="156dp" android:layout_height="156dp"
app:cardCornerRadius="16dp" android:layout_margin="8dp"
app:cardUseCompatPadding="true"> app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image" android:id="@+id/image"
@ -21,17 +21,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playSongs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="12dp"
android:background="@drawable/color_circle_gradient"
android:backgroundTint="@color/eighty_percent_black_overlay"
android:padding="8dp"
app:srcCompat="@drawable/ic_play_arrow_white_32dp" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer" android:id="@+id/imageContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="256dp" android:layout_height="256dp"
app:cardCornerRadius="16dp" android:layout_margin="8dp"
app:cardUseCompatPadding="true"> app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image" android:id="@+id/image"
@ -22,16 +22,6 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playSongs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="12dp"
android:background="@drawable/color_circle_gradient"
android:backgroundTint="@color/eighty_percent_black_overlay"
android:padding="8dp"
app:srcCompat="@drawable/ic_play_arrow_white_32dp" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer" android:id="@+id/imageContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="196dp" android:layout_height="196dp"
app:cardCornerRadius="16dp" android:layout_margin="8dp"
app:cardUseCompatPadding="true"> app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image" android:id="@+id/image"
@ -22,16 +22,6 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playSongs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="12dp"
android:background="@drawable/color_circle_gradient"
android:backgroundTint="@color/eighty_percent_black_overlay"
android:padding="8dp"
app:srcCompat="@drawable/ic_play_arrow_white_32dp" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView

View file

@ -48,7 +48,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:text="@string/songs" android:text="@string/songs"
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline6"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View file

@ -85,6 +85,26 @@
android:maxLines="1" /> android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/artistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/artistText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:hint="@string/artist"
android:inputType="text|textCapWords"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/albumArtistContainer" android:id="@+id/albumArtistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"

View file

@ -43,7 +43,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="12dp" android:padding="12dp"
android:text="@string/albums" android:text="@string/albums"
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline6"
android:textStyle="bold" android:textStyle="bold"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -69,7 +69,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:text="@string/songs" android:text="@string/songs"
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline6"
android:textStyle="bold" android:textStyle="bold"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -83,8 +83,7 @@
android:nestedScrollingEnabled="false" android:nestedScrollingEnabled="false"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/songTitle" app:layout_constraintTop_toBottomOf="@id/songTitle"
tools:listitem="@layout/item_song" tools:listitem="@layout/item_song" />
tools:visibility="gone" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/biographyTitle" android:id="@+id/biographyTitle"
@ -92,7 +91,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:text="@string/biography" android:text="@string/biography"
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline6"
android:textStyle="bold" android:textStyle="bold"
android:visibility="gone" android:visibility="gone"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
@ -104,13 +103,13 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/biographyText" android:id="@+id/biographyText"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:lineSpacingExtra="5dp" android:lineSpacingExtra="5dp"
android:maxLines="4" android:maxLines="4"
android:padding="16dp" android:padding="16dp"
android:textAppearance="@style/TextViewBody1"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View file

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:clickable="true" android:clickable="true"
android:focusable="true"> android:focusable="true">
@ -18,10 +19,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/shadow_up_full_theme" /> android:background="@drawable/shadow_up_full_theme" />
<View
android:id="@+id/mask"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -5,20 +5,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clickable="true" android:clickable="true"
android:background="?attr/colorSurface"
android:focusable="true"> android:focusable="true">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/colorBackground" android:id="@+id/colorBackground"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:scaleType="centerCrop" /> android:scaleType="centerCrop" />
<View
android:id="@+id/mask"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#20000000" />
<include layout="@layout/shadow_statusbar_toolbar" /> <include layout="@layout/shadow_statusbar_toolbar" />
@ -86,5 +82,4 @@
tools:layout="@layout/fragment_card_blur_player_playback_controls" /> tools:layout="@layout/fragment_card_blur_player_playback_controls" />
</FrameLayout> </FrameLayout>
</FrameLayout> </FrameLayout>
</FrameLayout> </FrameLayout>

View file

@ -12,58 +12,63 @@
android:id="@+id/playerMenu" android:id="@+id/playerMenu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="?attr/roundSelector" android:background="?attr/roundSelector"
android:padding="12dp" android:padding="8dp"
app:layout_constraintBottom_toBottomOf="@+id/text" app:layout_constraintBottom_toBottomOf="@+id/titleContainer"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_more_vert_white_24dp" /> app:srcCompat="@drawable/ic_more_vert_white_24dp" />
<com.google.android.material.textview.MaterialTextView <LinearLayout
android:id="@+id/title" android:id="@+id/titleContainer"
android:layout_width="315dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="marquee" android:orientation="vertical"
android:gravity="center"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:singleLine="true"
android:textAppearance="@style/TextViewHeadline6"
android:textColor="@color/md_white_1000"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text"
app:layout_constraintEnd_toStartOf="@+id/playerMenu"
app:layout_constraintStart_toEndOf="@+id/songFavourite"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text"
android:layout_width="315dp"
android:layout_height="wrap_content"
android:alpha="0.75"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:padding="8dp"
android:textColor="@color/md_white_1000"
app:layout_constraintBottom_toTopOf="@+id/progressSlider" app:layout_constraintBottom_toTopOf="@+id/progressSlider"
app:layout_constraintEnd_toStartOf="@+id/playerMenu" app:layout_constraintEnd_toStartOf="@+id/playerMenu"
app:layout_constraintStart_toEndOf="@+id/songFavourite" app:layout_constraintStart_toEndOf="@+id/songFavourite"
app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintTop_toTopOf="parent">
tools:layout_editor_absoluteX="48dp"
tools:text="@tools:sample/lorem/random" /> <com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="center"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:singleLine="true"
android:textAppearance="@style/TextViewHeadline6"
android:textColor="@color/md_white_1000"
android:textStyle="bold"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.75"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:padding="8dp"
android:textColor="@color/md_white_1000"
tools:text="@tools:sample/lorem/random" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/songFavourite" android:id="@+id/songFavourite"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:background="?attr/roundSelector" android:background="?attr/roundSelector"
android:padding="12dp" android:padding="8dp"
app:layout_constraintBottom_toBottomOf="@+id/text" app:layout_constraintBottom_toBottomOf="@+id/titleContainer"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/title" app:layout_constraintTop_toTopOf="@+id/titleContainer"
app:srcCompat="@drawable/ic_favorite_border_white_24dp" /> app:srcCompat="@drawable/ic_favorite_border_white_24dp" />
@ -95,7 +100,7 @@
android:splitTrack="false" android:splitTrack="false"
app:layout_constraintEnd_toStartOf="@id/songTotalTime" app:layout_constraintEnd_toStartOf="@id/songTotalTime"
app:layout_constraintStart_toEndOf="@id/songCurrentProgress" app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
app:layout_constraintTop_toBottomOf="@id/text" app:layout_constraintTop_toBottomOf="@id/titleContainer"
tools:ignore="RtlHardcoded,UnusedAttribute" tools:ignore="RtlHardcoded,UnusedAttribute"
tools:progress="20" /> tools:progress="20" />

View file

@ -47,7 +47,7 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:gravity="center_vertical" android:gravity="center_vertical"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic[16]" /> tools:srcCompat="@tools:sample/avatars" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/imageText" android:id="@+id/imageText"
@ -58,8 +58,7 @@
android:minHeight="40dp" android:minHeight="40dp"
android:textAppearance="@style/TextViewSubtitle2" android:textAppearance="@style/TextViewSubtitle2"
android:visibility="gone" android:visibility="gone"
tools:text="100" tools:text="100" />
tools:visibility="visible" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
</FrameLayout> </FrameLayout>

View file

@ -22,16 +22,6 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/playSongs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="12dp"
android:background="@drawable/color_circle_gradient"
android:backgroundTint="@color/eighty_percent_black_overlay"
android:padding="8dp"
app:srcCompat="@drawable/ic_play_arrow_white_32dp" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView

View file

@ -25,10 +25,25 @@
android:id="@+id/image" android:id="@+id/image"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/proText"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintTop_toBottomOf="@+id/title"
tools:src="@tools:sample/backgrounds/scenic" /> tools:src="@tools:sample/backgrounds/scenic" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/proText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/line_button"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="@string/pro"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,6 +8,7 @@
<item name="action_album_sort_order_desc" type="id" /> <item name="action_album_sort_order_desc" type="id" />
<item name="action_album_sort_order_artist" type="id" /> <item name="action_album_sort_order_artist" type="id" />
<item name="action_album_sort_order_year" type="id" /> <item name="action_album_sort_order_year" type="id" />
<item name="action_album_sort_num_songs" type="id" />
<item name="action_artist_sort_order_asc" type="id" /> <item name="action_artist_sort_order_asc" type="id" />
<item name="action_artist_sort_order_desc" type="id" /> <item name="action_artist_sort_order_desc" type="id" />
<item name="action_song_sort_order_asc" type="id" /> <item name="action_song_sort_order_asc" type="id" />

View file

@ -825,4 +825,6 @@
<string name="share_to_stories">Share to Stories</string> <string name="share_to_stories">Share to Stories</string>
<string name="drive_mode">Drive mode</string> <string name="drive_mode">Drive mode</string>
<string name="retro_music_player">Retro Music Player</string> <string name="retro_music_player">Retro Music Player</string>
<string name="sort_num_songs">Number of songs</string>
<string name="pro">Pro</string>
</resources> </resources>

View file

@ -7,6 +7,7 @@
<code.name.monkey.retromusic.preferences.BlacklistPreference <code.name.monkey.retromusic.preferences.BlacklistPreference
android:key="blacklist" android:key="blacklist"
app:enabled="false"
android:layout="@layout/list_item_view" android:layout="@layout/list_item_view"
android:summary="@string/pref_summary_blacklist" android:summary="@string/pref_summary_blacklist"
android:title="@string/pref_title_blacklist" android:title="@string/pref_title_blacklist"

View file

@ -54,12 +54,5 @@
android:summary="@string/pref_summary_colored_app_shortcuts" android:summary="@string/pref_summary_colored_app_shortcuts"
android:title="@string/pref_title_app_shortcuts" /> android:title="@string/pref_title_app_shortcuts" />
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
android:defaultValue="false"
android:key="dominant_color"
android:layout="@layout/list_item_view_switch"
android:summary="@string/pref_summary_dominant_color"
android:title="@string/pref_title_toggle_dominant_color" />
</code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory> </code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>

View file

@ -35,48 +35,6 @@ import java.lang.reflect.Field;
*/ */
public final class TintHelper { public final class TintHelper {
@SuppressWarnings("JavaReflectionMemberAccess")
public static void colorHandles(@NonNull TextView view, int color) {
try {
Field editorField = TextView.class.getDeclaredField("mEditor");
if (!editorField.isAccessible()) {
editorField.setAccessible(true);
}
Object editor = editorField.get(view);
Class<?> editorClass = editor.getClass();
String[] handleNames = {"mSelectHandleLeft", "mSelectHandleRight", "mSelectHandleCenter"};
String[] resNames = {"mTextSelectHandleLeftRes", "mTextSelectHandleRightRes", "mTextSelectHandleRes"};
for (int i = 0; i < handleNames.length; i++) {
Field handleField = editorClass.getDeclaredField(handleNames[i]);
if (!handleField.isAccessible()) {
handleField.setAccessible(true);
}
Drawable handleDrawable = (Drawable) handleField.get(editor);
if (handleDrawable == null) {
Field resField = TextView.class.getDeclaredField(resNames[i]);
if (!resField.isAccessible()) {
resField.setAccessible(true);
}
int resId = resField.getInt(view);
handleDrawable = view.getResources().getDrawable(resId);
}
if (handleDrawable != null) {
Drawable drawable = handleDrawable.mutate();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
handleField.set(editor, drawable);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@CheckResult @CheckResult
@NonNull @NonNull
public static Drawable createTintedDrawable(Context context, public static Drawable createTintedDrawable(Context context,

Some files were not shown because too many files have changed in this diff Show more