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
applicationId "code.name.monkey.retromusic"
versionCode 405
versionName '3.4.900'
versionCode 408
versionName '3.5.000'
multiDexEnabled true
@ -129,8 +129,8 @@ dependencies {
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.fragment:fragment:1.2.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.fragment:fragment:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
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 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
MediaStore.Audio.AudioColumns.TITLE, // 1

View file

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

View file

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

View file

@ -129,7 +129,7 @@ class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDet
})
}
override fun songs(songs: ArrayList<Song>) {
override fun songs(songs: List<Song>) {
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.SearchQueryHelper
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.loaders.ArtistLoader
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater
@ -155,14 +153,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
//MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true
}
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
//MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
handled = true
}
}
@ -220,7 +218,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
}
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()
}

View file

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

View file

@ -40,7 +40,7 @@ import java.util.Collections
abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected var id: Int = 0
protected var id: Long = 0
private set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
@ -187,22 +187,16 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
setUpViews()
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
}
private fun setUpViews() {
setUpScrollView()
setUpFab()
setUpImageView()
}
private fun setUpScrollView() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
}
private lateinit var items: List<String>
private fun setUpImageView() {
@ -261,7 +255,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID)
id = intentExtras.getLong(EXTRA_ID)
}
}
@ -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 {
@ -415,5 +409,4 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val TAG = AbsTagEditorActivity::class.java.simpleName
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.MaterialUtil
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.glide.palette.BitmapPaletteTranscoder
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.albumText
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.genreTitle
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.yearTitle
import org.jaudiotagger.tag.FieldKey
import java.util.ArrayList
import java.util.EnumMap
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
@ -58,7 +58,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
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)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
@ -115,15 +117,18 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(artistContainer, false)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
genreTitle.appHandleColor().addTextChangedListener(this)
yearTitle.appHandleColor().addTextChangedListener(this)
albumText.addTextChangedListener(this)
artistText.addTextChangedListener(this)
albumArtistText.addTextChangedListener(this)
genreTitle.addTextChangedListener(this)
yearTitle.addTextChangedListener(this)
}
private fun fillViewsWithFileTags() {
albumText.setText(albumTitle)
artistText.setText(artistName)
albumArtistText.setText(albumArtistName)
genreTitle.setText(genreName)
yearTitle.setText(songYear)
@ -141,10 +146,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
deleteAlbumArt = false
}
override fun onPause() {
super.onPause()
}
private fun toastLoadingFailed() {
Toast.makeText(
this@AlbumTagEditorActivity,
@ -170,21 +171,24 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
//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.GENRE] = genreTitle.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString()
writeValuesToFiles(
fieldKeyValueMap,
if (deleteAlbumArt) ArtworkInfo(id, null)
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
when {
deleteAlbumArt -> ArtworkInfo(id, null)
albumArtBitmap == null -> null
else -> ArtworkInfo(id, albumArtBitmap!!)
}
)
}
override fun getSongPaths(): List<String> {
val songs = AlbumLoader.getAlbum(this, id).songs
val paths = ArrayList<String>(songs!!.size)
val songs = AlbumLoader.getSongsForAlbum(this, id)
val paths = ArrayList<String>(songs.size)
for (song in songs) {
paths.add(song.data)
}
@ -207,7 +211,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
}
companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName
}
}

View file

@ -6,7 +6,6 @@ import android.text.Editable
import android.text.TextWatcher
import code.name.monkey.appthemehelper.util.MaterialUtil
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.loaders.SongLoader
import kotlinx.android.synthetic.main.activity_song_tag_editor.albumArtistContainer
@ -43,7 +42,6 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
setNoImageMode()
setUpViews()
applyToolbar(toolbar)
}
private fun setUpViews() {
@ -58,15 +56,15 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
MaterialUtil.setTint(trackNumberContainer, false)
MaterialUtil.setTint(lyricsContainer, false)
songText.appHandleColor().addTextChangedListener(this)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
artistText.appHandleColor().addTextChangedListener(this)
genreText.appHandleColor().addTextChangedListener(this)
yearText.appHandleColor().addTextChangedListener(this)
trackNumberText.appHandleColor().addTextChangedListener(this)
lyricsText.appHandleColor().addTextChangedListener(this)
songComposerText.appHandleColor().addTextChangedListener(this)
songText.addTextChangedListener(this)
albumText.addTextChangedListener(this)
albumArtistText.addTextChangedListener(this)
artistText.addTextChangedListener(this)
genreText.addTextChangedListener(this)
yearText.addTextChangedListener(this)
trackNumberText.addTextChangedListener(this)
lyricsText.addTextChangedListener(this)
songComposerText.addTextChangedListener(this)
}
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.model.Genre
import code.name.monkey.retromusic.util.NavigationUtil
import java.util.ArrayList
import java.util.Locale
/**
@ -18,11 +17,11 @@ import java.util.Locale
class GenreAdapter(
private val activity: Activity,
dataSet: ArrayList<Genre>,
dataSet: List<Genre>,
private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
var dataSet = ArrayList<Genre>()
var dataSet = listOf<Genre>()
private set
init {
@ -48,7 +47,7 @@ class GenreAdapter(
return dataSet.size
}
fun swapDataSet(list: ArrayList<Genre>) {
fun swapDataSet(list: List<Genre>) {
dataSet = list
notifyDataSetChanged()
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -34,7 +34,7 @@ import java.util.ArrayList
class PlaylistAdapter(
private val activity: AppCompatActivity,
var dataSet: ArrayList<Playlist>,
var dataSet: List<Playlist>,
private var itemLayoutRes: Int,
cabHolder: CabHolder?
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(
@ -49,7 +49,7 @@ class PlaylistAdapter(
setHasStableIds(true)
}
fun swapDataSet(dataSet: ArrayList<Playlist>) {
fun swapDataSet(dataSet: List<Playlist>) {
this.dataSet = dataSet
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.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import java.util.ArrayList
abstract class AbsOffsetSongAdapter(
activity: AppCompatActivity,
dataSet: ArrayList<Song>,
dataSet: MutableList<Song>,
@LayoutRes itemLayoutRes: Int,
cabHolder: CabHolder?
) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {

View file

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

View file

@ -7,11 +7,10 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import com.google.android.material.button.MaterialButton
import java.util.ArrayList
class ShuffleButtonSongAdapter(
activity: AppCompatActivity,
dataSet: ArrayList<Song>,
dataSet: MutableList<Song>,
itemLayoutRes: Int,
cabHolder: 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.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import java.util.ArrayList
class SimpleSongAdapter(
context: AppCompatActivity,
songs: ArrayList<Song>,
songs: MutableList<Song>,
layoutRes: Int,
cabHolder: CabHolder?
) : SongAdapter(context, songs, layoutRes, cabHolder) {
override fun swapDataSet(dataSet: ArrayList<Song>) {
this.dataSet.clear()
this.dataSet = dataSet
override fun swapDataSet(dataSet: List<Song>) {
this.dataSet = dataSet.toMutableList()
notifyDataSetChanged()
}

View file

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

View file

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

View file

@ -29,8 +29,8 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems
import java.io.File
import java.util.*
import kotlin.collections.ArrayList
import java.util.Collections
import java.util.Comparator
class BlacklistFolderChooserDialog : DialogFragment() {
@ -40,7 +40,6 @@ class BlacklistFolderChooserDialog : DialogFragment() {
private var canGoUp = false
private var callback: FolderCallback? = null
private fun contentsArray(): List<String> {
if (parentContents == null) {
return if (canGoUp) {
@ -81,7 +80,11 @@ class BlacklistFolderChooserDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
var savedInstanceStateFinal = savedInstanceState
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 {
title(R.string.md_error_label)
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.layout
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.util.PlaylistsUtil
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.TextInputLayout
class CreatePlaylistDialog : DialogFragment() {
private lateinit var playlistView: TextInputEditText
private lateinit var actionNewPlaylistContainer: TextInputLayout
override fun onCreateDialog(
savedInstanceState: Bundle?
savedInstanceState: Bundle?
): Dialog {
val materialDialog = MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT))
.show {
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
title(string.new_playlist_title)
customView(layout.dialog_playlist)
negativeButton(android.R.string.cancel)
positiveButton(string.create_action) {
if (activity == null) {
return@positiveButton
}
val songs = arguments?.getParcelableArrayList<Song>("songs")
?: return@positiveButton
.show {
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
title(string.new_playlist_title)
customView(layout.dialog_playlist)
negativeButton(android.R.string.cancel)
positiveButton(string.create_action) {
if (activity == null) {
return@positiveButton
}
val songs = arguments?.getParcelableArrayList<Song>("songs")
?: return@positiveButton
if (playlistView.text.toString().trim { it <= ' ' }.isNotEmpty()) {
val playlistId = PlaylistsUtil.createPlaylist(requireContext(), playlistView.text.toString())
if (playlistId != -1 && activity != null) {
PlaylistsUtil.addToPlaylist(requireContext(), songs, playlistId, true)
}
if (playlistView.text.toString().trim { it <= ' ' }.isNotEmpty()) {
val playlistId = PlaylistsUtil.createPlaylist(requireContext(), playlistView.text.toString())
if (playlistId != -1 && activity != null) {
PlaylistsUtil.addToPlaylist(requireContext(), songs, playlistId, true)
}
}
}
}
val dialogView = materialDialog.getCustomView()
playlistView = dialogView.findViewById(R.id.actionNewPlaylist)
@ -73,7 +71,10 @@ class CreatePlaylistDialog : DialogFragment() {
MaterialUtil.setTint(actionNewPlaylistContainer, false)
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
}

View file

@ -104,10 +104,10 @@ class DeleteSongsDialog : DialogFragment() {
return create(list)
}
fun create(songs: ArrayList<Song>): DeleteSongsDialog {
fun create(songs: List<Song>): DeleteSongsDialog {
val dialog = DeleteSongsDialog()
val args = Bundle()
args.putParcelableArrayList("songs", songs)
args.putParcelableArrayList("songs", ArrayList(songs))
dialog.arguments = args
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.layout
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.PreferenceUtil
import com.afollestad.materialdialogs.LayoutMode
@ -60,7 +59,7 @@ class RenamePlaylistDialog : DialogFragment() {
MaterialUtil.setTint(actionNewPlaylistContainer, false)
val playlistId = arguments!!.getLong(PLAYLIST_ID)
playlistView.appHandleColor()
playlistView
.setText(PlaylistsUtil.getNameForPlaylist(context!!, playlistId), TextView.BufferType.EDITABLE)
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.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.annotation.LayoutRes
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.TintHelper
@Suppress("UNCHECKED_CAST")
fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T {
@ -40,9 +36,4 @@ fun View.hidden() {
visibility = View.INVISIBLE
}
fun View.showOrHide(show: Boolean) = if (show) show() else hide()
fun EditText.appHandleColor(): EditText {
TintHelper.colorHandles(this, ThemeStore.accentColor(context))
return this
}
fun View.showOrHide(show: Boolean) = if (show) show() else hide()

View file

@ -10,21 +10,19 @@ enum class NowPlayingScreen constructor(
@param:DrawableRes @field:DrawableRes val drawableResId: 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),
BLUR(R.string.blur, R.drawable.np_blur, 4),
BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9),
CARD(R.string.card, R.drawable.np_card, 6),
COLOR(R.string.color, R.drawable.np_color, 5),
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),
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),
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) {
setLayoutRes(layoutRes)
saveLayoutRes(layoutRes)
invalidateAdapter()
}
private val maxGridSizeForList: Int
@ -118,12 +119,6 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A : RecyclerVie
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 saveLayoutRes(layoutRes: Int)

View file

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

View file

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

View file

@ -16,7 +16,7 @@ import javax.inject.Inject
class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
ArtistsView {
override fun artists(artists: ArrayList<Artist>) {
override fun artists(artists: List<Artist>) {
adapter?.swapDataSet(artists)
}
@ -66,7 +66,6 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
libraryFragment.mainActivity,
dataSet,
itemLayoutRes(),
loadUsePalette(),
libraryFragment
)
}
@ -87,18 +86,6 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
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) {
layoutManager?.spanCount = gridSize
adapter?.notifyDataSetChanged()
@ -121,9 +108,7 @@ class ArtistsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<Artist
val TAG: String = ArtistsFragment::class.java.simpleName
fun newInstance(): ArtistsFragment {
val args = Bundle()
val fragment = ArtistsFragment()
fragment.arguments = args
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 javax.inject.Inject
class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(), GenresView {
override fun genres(genres: ArrayList<Genre>) {
override fun genres(genres: List<Genre>) {
adapter?.swapDataSet(genres)
}
override fun showEmptyView() {
}
override fun createLayoutManager(): LinearLayoutManager {
@ -48,11 +46,9 @@ class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearL
override val emptyMessage: Int
get() = R.string.no_genres
@Inject
lateinit var genresPresenter: GenresPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
App.musicComponent.inject(this)
@ -62,6 +58,7 @@ class GenresFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearL
super.onViewCreated(view, savedInstanceState)
genresPresenter.attachView(this)
}
override fun onResume() {
super.onResume()
if (adapter!!.dataSet.isEmpty()) {

View file

@ -1,5 +1,9 @@
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.ActivityOptions;
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.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment;
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.MainActivityFragmentCallbacks;
import code.name.monkey.retromusic.util.NavigationUtil;
@ -301,49 +304,52 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
if (fragment instanceof AlbumsFragment) {
switch (item.getItemId()) {
case R.id.action_album_sort_order_asc:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_A_Z;
sortOrder = AlbumSortOrder.ALBUM_A_Z;
break;
case R.id.action_album_sort_order_desc:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_Z_A;
sortOrder = AlbumSortOrder.ALBUM_Z_A;
break;
case R.id.action_album_sort_order_artist:
sortOrder = SortOrder.AlbumSortOrder.ALBUM_ARTIST;
sortOrder = AlbumSortOrder.ALBUM_ARTIST;
break;
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;
}
} else if (fragment instanceof ArtistsFragment) {
switch (item.getItemId()) {
case R.id.action_artist_sort_order_asc:
sortOrder = SortOrder.ArtistSortOrder.ARTIST_A_Z;
sortOrder = ArtistSortOrder.ARTIST_A_Z;
break;
case R.id.action_artist_sort_order_desc:
sortOrder = SortOrder.ArtistSortOrder.ARTIST_Z_A;
sortOrder = ArtistSortOrder.ARTIST_Z_A;
break;
}
} else if (fragment instanceof SongsFragment) {
switch (item.getItemId()) {
case R.id.action_song_sort_order_asc:
sortOrder = SortOrder.SongSortOrder.SONG_A_Z;
sortOrder = SongSortOrder.SONG_A_Z;
break;
case R.id.action_song_sort_order_desc:
sortOrder = SortOrder.SongSortOrder.SONG_Z_A;
sortOrder = SongSortOrder.SONG_Z_A;
break;
case R.id.action_song_sort_order_artist:
sortOrder = SortOrder.SongSortOrder.SONG_ARTIST;
sortOrder = SongSortOrder.SONG_ARTIST;
break;
case R.id.action_song_sort_order_album:
sortOrder = SortOrder.SongSortOrder.SONG_ALBUM;
sortOrder = SongSortOrder.SONG_ALBUM;
break;
case R.id.action_song_sort_order_year:
sortOrder = SortOrder.SongSortOrder.SONG_YEAR;
sortOrder = SongSortOrder.SONG_YEAR;
break;
case R.id.action_song_sort_order_date:
sortOrder = SortOrder.SongSortOrder.SONG_DATE;
sortOrder = SongSortOrder.SONG_DATE;
break;
case R.id.action_song_sort_order_composer:
sortOrder = SortOrder.SongSortOrder.COMPOSER;
sortOrder = SongSortOrder.COMPOSER;
break;
}
@ -452,33 +458,35 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
if (fragment instanceof AlbumsFragment) {
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)
.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)
.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)
.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) {
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)
.setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_Z_A));
.setChecked(currentSortOrder.equals(ArtistSortOrder.ARTIST_Z_A));
} else if (fragment instanceof SongsFragment) {
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)
.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)
.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)
.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)
.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)
.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)
.setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.COMPOSER));
.setChecked(currentSortOrder.equals(SongSortOrder.COMPOSER));
}
sortOrderMenu.setGroupCheckable(0, true, true);

View file

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

View file

@ -40,7 +40,7 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
}
override fun createAdapter(): SongAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
return ShuffleButtonSongAdapter(
libraryFragment.mainActivity,
dataSet,
@ -49,7 +49,7 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
)
}
override fun songs(songs: ArrayList<Song>) {
override fun songs(songs: List<Song>) {
adapter?.swapDataSet(songs)
}
@ -73,17 +73,6 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdap
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) {
adapter?.notifyDataSetChanged()
}

View file

@ -99,7 +99,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
private fun updateBlur() {
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
colorBackground!!.clearColorFilter()
colorBackground?.clearColorFilter()
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext())
.generatePalette(requireContext()).build()
@ -109,7 +109,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
.into(object : RetroMusicColoredTarget(colorBackground) {
override fun onColorReady(color: Int) {
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.player.PlayerAlbumCoverFragment
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.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
@ -53,7 +53,7 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
override fun onColorChanged(color: Int) {
playbackControlsFragment.setDark(color)
lastColor = color
callbacks!!.onPaletteColorChanged()
callbacks?.onPaletteColorChanged()
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
playerToolbar.setTitleTextColor(Color.WHITE)
@ -127,10 +127,19 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
}
private fun updateBlur() {
colorBackground?.clearColorFilter()
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
colorBackground!!.clearColorFilter()
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), MusicPlayerRemote.currentSong.albumId)
.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())
.generatePalette(requireContext()).build()
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
@ -138,11 +147,9 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
//.override(320, 480)
.into(object : RetroMusicColoredTarget(colorBackground) {
override fun onColorReady(color: Int) {
if (color == defaultFooterColor) {
colorBackground!!.setColorFilter(color)
}
}
})
})*/
}
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.ViewUtil
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() {
@ -30,18 +30,21 @@ class PlayerFragment : AbsPlayerFragment() {
private lateinit var playbackControlsFragment: PlayerPlaybackControlsFragment
private var valueAnimator: ValueAnimator? = null
private fun colorize(i: Int) {
if (valueAnimator != null) {
valueAnimator?.cancel()
}
valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), ATHUtil.resolveColor(requireContext(), R.attr.colorSurface), i)
valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), lastColor, i)
valueAnimator?.addUpdateListener { animation ->
if (isAdded) {
val drawable = DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(animation.animatedValue as Int,
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)), 0)
val drawable = DrawableGradient(
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(
animation.animatedValue as Int,
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)
), 0
)
colorGradientBackground?.background = drawable
}
}
@ -70,7 +73,11 @@ class PlayerFragment : AbsPlayerFragment() {
lastColor = color
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) {
colorize(color)
@ -88,9 +95,10 @@ class PlayerFragment : AbsPlayerFragment() {
toggleFavorite(MusicPlayerRemote.currentSong)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_player, container, false)
}
@ -101,19 +109,24 @@ class PlayerFragment : AbsPlayerFragment() {
setUpPlayerToolbar()
}
private fun setUpSubFragments() {
playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playbackControlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
val playerAlbumCoverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playerAlbumCoverFragment.setCallbacks(this)
}
private fun setUpPlayerToolbar() {
playerToolbar.inflateMenu(R.menu.menu_player)
playerToolbar.setNavigationOnClickListener {requireActivity().onBackPressed() }
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
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() {

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,89 +15,136 @@
package code.name.monkey.retromusic.loaders
import android.content.Context
import android.provider.MediaStore.Audio.AudioColumns
import android.database.Cursor
import android.provider.BaseColumns
import android.provider.MediaStore
import 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.Song
import code.name.monkey.retromusic.util.PreferenceUtil
import java.util.*
import kotlin.collections.ArrayList
import android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI as SONGS_URI
/**
* Created by hemanths on 11/08/17.
*/
object AlbumLoader {
object AlbumLoader {
fun getAlbums(
context: Context,
query: String
): ArrayList<Album> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
AudioColumns.ALBUM + " LIKE ?",
arrayOf("%$query%"),
getSongLoaderSortOrder(context))
fun getAllAlbums(context: Context): List<Album> {
return makeAlbumCursor(context, null, null)
.mapList(true) {
Album.fromCursor(this)
}
}
fun getAlbum(context: Context, id: Long): Album {
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(
context: Context,
albumId: Int
): Album {
val songs = SongLoader.getSongs(
SongLoader.makeSongCursor(
context,
AudioColumns.ALBUM_ID + "=?",
arrayOf(albumId.toString()),
getSongLoaderSortOrder(context)))
val album = Album(songs)
sortSongsByTrackNumber(album)
return album
private fun getAlbum(cursor: Cursor?): Album {
return cursor?.use {
if (cursor.moveToFirst()) {
Album.fromCursor(cursor)
} else {
null
}
} ?: Album()
}
fun getAllAlbums(
context: Context
): ArrayList<Album> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, null, null, getSongLoaderSortOrder(context)))
return splitIntoAlbums(songs)
private fun makeAlbumCursor(context: Context, selection: String?, paramArrayOfString: Array<String>?): Cursor? {
return context.contentResolver.query(
EXTERNAL_CONTENT_URI,
arrayOf(
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(
songs: ArrayList<Song>?
songs: ArrayList<Song>?
): ArrayList<Album> {
val albums = ArrayList<Album>()
if (songs != null) {
for (song in songs) {
getOrCreateAlbum(albums, song.albumId).songs?.add(song)
getOrCreateAlbum(albums, song)
}
}
for (album in albums) {
sortSongsByTrackNumber(album)
}
return albums
}
private fun getOrCreateAlbum(
albums: ArrayList<Album>,
albumId: Int
albums: ArrayList<Album>,
song: Song
): Album {
for (album in albums) {
if (album.songs!!.isNotEmpty() && album.songs[0].albumId == albumId) {
if (album.id == song.albumId) {
return album
}
}
val album = Album()
val album = Album.fromSong(song)
albums.add(album)
return album
}
private fun sortSongsByTrackNumber(album: Album) {
album.songs?.sortWith(Comparator { o1, o2 -> o1.trackNumber.compareTo(o2.trackNumber) })
}
private fun getSongLoaderSortOrder(context: Context): String {
return PreferenceUtil.getInstance(context).albumSortOrder + ", " + PreferenceUtil.getInstance(context).albumSongSortOrder
fun getAlbums(context: Context, paramString: String): List<Album> {
return makeAlbumCursor(context, "album LIKE ?", arrayOf("$paramString%"))
.mapList(true) { Album.fromCursor(this) }
}
}
/*
* 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
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.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
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> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
null, null,
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
return getArtists(makeArtistCursor(context, null, null))
}
fun getArtists(context: Context, query: String): ArrayList<Artist> {
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
AudioColumns.ARTIST + " LIKE ?",
arrayOf("%$query%"),
getSongLoaderSortOrder(context))
)
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
fun getArtist(context: Context, artistId: Long): Artist {
return getArtist(makeArtistCursor(context, "_id=?", arrayOf(artistId.toString())))
}
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>()
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) {
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
getOrCreateArtist(artists, album)
}
}
return artists
}
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist {
private fun getOrCreateArtist(artists: ArrayList<Artist>, album: Album): Artist {
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
}
}
val album = Artist()
artists.add(album)
return album
val a = Artist.fromAlbum(album)
artists.add(a)
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.provider.BaseColumns
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.model.Genre
import code.name.monkey.retromusic.model.Song
@ -94,7 +94,7 @@ object GenreLoader {
try {
return context.contentResolver.query(
Genres.Members.getContentUri("external", genreId.toLong()),
baseProjection, BASE_SELECTION, null, PreferenceUtil.getInstance(context).songSortOrder)
baseProjection, baseSelection, null, PreferenceUtil.getInstance(context).songSortOrder)
} catch (e: SecurityException) {
return null
}

View file

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

View file

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

View file

@ -18,10 +18,9 @@ import android.content.Context
import android.database.Cursor
import android.provider.MediaStore
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.baseSelection
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.PreferenceUtil
import java.util.ArrayList
@ -61,7 +60,7 @@ object SongLoader {
return getSongs(cursor)
}
fun getSong(
private fun getSong(
cursor: Cursor?
): Song {
val song: Song
@ -75,98 +74,79 @@ object SongLoader {
}
@JvmStatic
fun getSong(context: Context, queryId: Int): Song {
fun getSong(context: Context, queryId: Long): Song {
val cursor = makeSongCursor(context, AudioColumns._ID + "=?", arrayOf(queryId.toString()))
return getSong(cursor)
}
private fun getSongFromCursorImpl(
cursor: Cursor
): Song {
val id = cursor.getInt(0)
val title = cursor.getString(1)
val trackNumber = cursor.getInt(2)
val year = cursor.getInt(3)
val duration = cursor.getLong(4)
val data = cursor.getString(5)
val dateModified = cursor.getLong(6)
val albumId = cursor.getInt(7)
val albumName = cursor.getString(8)
val artistId = cursor.getInt(9)
val artistName = cursor.getString(10)
val composer = cursor.getString(11)
return Song(
id, title, trackNumber, year, duration, data, dateModified, albumId,
albumName ?: "", artistId, artistName, composer ?: ""
)
}
): Song = Song.fromCursor(cursor)
@JvmStatic
@JvmOverloads
fun makeSongCursor(
context: Context,
selection: String?,
selectionValues: Array<String>?,
selectionString: String?,
selectionValuesArray: Array<String>?,
sortOrder: String = PreferenceUtil.getInstance(context).songSortOrder
): Cursor? {
var selectionFinal = selection
var selectionValuesFinal = selectionValues
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") {
"$BASE_SELECTION AND $selectionFinal"
): Cursor {
var selectionValues: Array<String>? = arrayOf()
var selection = if (selectionString != null && selectionString.trim() != "") {
"$baseSelection AND $selectionString"
} else {
BASE_SELECTION
baseSelection
}
// Blacklist
val paths = BlacklistStore.getInstance(context).paths
/*val paths = BlacklistStore.getInstance(context).paths
if (paths.isNotEmpty()) {
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
selection = generateBlacklistSelection(selection, paths.size)
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(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
baseProjection,
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.getInstance(
context
).filterLength * 1000),
selectionValuesFinal,
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
return context.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
baseProjection,
selection,
selectionValuesArray,
sortOrder
)
?: throw IllegalStateException("Unable to query ${MediaStore.Audio.Media.EXTERNAL_CONTENT_URI}, system returned null.")
}
}
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> {
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
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 {
val songs: ArrayList<Song>?
data class Album(
var id: Long = 0,
var title: String = "",
var artist: String = "",
var artistId: Long = 0,
var songCount: Int = 0,
var year: Int = 0
) {
val id: Int
get() = safeGetFirstSong().albumId
companion object {
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?
get() = safeGetFirstSong().albumName
val artistId: Int
get() = safeGetFirstSong().artistId
val artistName: String?
get() = safeGetFirstSong().artistName
val year: Int
get() = safeGetFirstSong().year
val dateModified: Long
get() = safeGetFirstSong().dateModified
val songCount: Int
get() = songs!!.size
constructor(songs: ArrayList<Song>) {
this.songs = songs
}
constructor() {
this.songs = ArrayList()
}
fun safeGetFirstSong(): Song {
return if (songs!!.isEmpty()) Song.emptySong else songs[0]
fun fromSong(song: Song): Album {
return Album(song.albumId, song.albumName, song.artistName, song.artistId, -1, song.year)
}
}
}
fun Cursor.valueOrEmpty(name: String): String = valueOrDefault(name, "")
inline fun <reified T> Cursor.value(name: String): T {
val index = getColumnIndexOrThrow(name)
return when (T::class) {
Short::class -> getShort(index) as T
Int::class -> getInt(index) as T
Long::class -> getLong(index) as T
Boolean::class -> (getInt(index) == 1) as T
String::class -> getString(index) as T
Float::class -> getFloat(index) as T
Double::class -> getDouble(index) as T
ByteArray::class -> getBlob(index) as T
else -> throw IllegalStateException("What do I do with ${T::class.java.simpleName}?")
}
}
inline fun <reified T> Cursor.valueOrDefault(name: String, defaultValue: T): T {
val index = getColumnIndex(name)
if (index == -1) {
return defaultValue
}
return when (T::class) {
Short::class -> getShort(index) as? T ?: defaultValue
Int::class -> getInt(index) as? T ?: defaultValue
Long::class -> getLong(index) as? T ?: defaultValue
Boolean::class -> (getInt(index) == 1) as T
String::class -> getString(index) as? T ?: defaultValue
Float::class -> getFloat(index) as? T ?: defaultValue
Double::class -> getDouble(index) as? T ?: defaultValue
ByteArray::class -> getBlob(index) as? T ?: defaultValue
else -> throw IllegalStateException("What do I do with ${T::class.java.simpleName}?")
}
}

View file

@ -14,57 +14,34 @@
package code.name.monkey.retromusic.model
import code.name.monkey.retromusic.util.MusicUtil
import java.util.ArrayList
import android.database.Cursor
import android.provider.MediaStore.Audio.Artists.ARTIST
import android.provider.MediaStore.Audio.Artists.NUMBER_OF_ALBUMS
import android.provider.MediaStore.Audio.Artists.NUMBER_OF_TRACKS
import android.provider.MediaStore.Audio.Artists._ID
class Artist {
val albums: ArrayList<Album>?
val id: Int
get() = safeGetFirstAlbum().artistId
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]
}
class Artist(
var id: Long = 0,
var name: String = "",
var songCount: Int = 0,
var albumCount: Int = 0
) {
companion object {
fun fromCursor(cursor: Cursor): Artist {
return Artist(
id = cursor.value(_ID),
name = cursor.value(ARTIST),
songCount = cursor.value(NUMBER_OF_TRACKS),
albumCount = cursor.value(NUMBER_OF_ALBUMS)
)
}
fun fromAlbum(album: Album): Artist {
return Artist(album.artistId, album.artist, -1, -1)
}
const val UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"
}
}

View file

@ -13,21 +13,23 @@
*/
package code.name.monkey.retromusic.model
import android.database.Cursor
import android.os.Parcelable
import android.provider.MediaStore.Audio.Media
import kotlinx.android.parcel.Parcelize
@Parcelize
open class Song(
val id: Int,
val id: Long,
val title: String,
val trackNumber: Int,
val year: Int,
val duration: Long,
val data: String,
val dateModified: Long,
val albumId: Int,
val albumId: Long,
val albumName: String,
val artistId: Int,
val artistId: Long,
val artistName: String,
val composer: String?
) : Parcelable {
@ -49,5 +51,22 @@ open class Song(
"",
""
)
fun fromCursor(cursor: Cursor, 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.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository
@ -36,21 +37,24 @@ interface AlbumDetailsView {
fun album(album: Album)
fun songs(songs: List<Song>)
fun complete()
fun loadArtistImage(artist: Artist)
fun moreAlbums(
albums: ArrayList<Album>
)
fun moreAlbums(albums: List<Album>)
fun aboutAlbum(lastFmAlbum: LastFmAlbum)
}
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)
class AlbumDetailsPresenterImpl @Inject constructor(
@ -60,7 +64,7 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private val job = Job()
private lateinit var album: Album
override fun loadMore(artistId: Int) {
override fun loadMore(artistId: Long) {
launch {
when (val result = repository.artistById(artistId)) {
is Success -> withContext(Dispatchers.Main) { showArtistImage(result.data) }
@ -80,13 +84,9 @@ interface AlbumDetailsPresenter : Presenter<AlbumDetailsView> {
private fun showArtistImage(artist: 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 {
when (val result = repository.albumById(albumId)) {
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() {
super.detachView()
job.cancel()

View file

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

View file

@ -14,8 +14,10 @@
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.Song
import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl
@ -35,14 +37,24 @@ import kotlin.coroutines.CoroutineContext
*/
interface ArtistDetailsView : BaseView {
fun songs(songs: List<Song>)
fun albums(albums: List<Album>)
fun artist(artist: Artist)
fun artistInfo(lastFmArtist: LastFmArtist?)
fun complete()
}
interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
fun loadArtist(artistId: Int)
fun loadArtist(artistId: Long)
fun loadArtistSongs(artistId: Long)
fun loadArtistAlbums(artistId: Long)
fun loadBiography(
name: String,
@ -62,26 +74,35 @@ interface ArtistDetailsPresenter : Presenter<ArtistDetailsView> {
override fun loadBiography(name: String, lang: String?, cache: String?) {
launch {
when (val result = repository.artistInfo(name, lang, cache)) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.artistInfo(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) {
}
is Success -> withContext(Dispatchers.Main) { view?.artistInfo(result.data) }
is Error -> withContext(Dispatchers.Main) {}
}
}
}
override fun loadArtist(artistId: Int) {
override fun loadArtist(artistId: Long) {
launch {
when (val result = repository.artistById(artistId)) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.artist(result.data)
is Success -> withContext(Dispatchers.Main) { view?.artist(result.data) }
is Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
}
is Result.Error -> withContext(Dispatchers.Main) {
view?.showEmptyView()
}
override fun loadArtistSongs(artistId: Long) {
launch {
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.PresenterImpl
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 kotlin.coroutines.CoroutineContext
interface ArtistsView : BaseView {
fun artists(artists: ArrayList<Artist>)
fun artists(artists: List<Artist>)
}
interface ArtistsPresenter : Presenter<ArtistsView> {
@ -33,8 +37,9 @@ interface ArtistsPresenter : Presenter<ArtistsView> {
fun loadArtists()
class ArtistsPresenterImpl @Inject constructor(
private val repository: Repository
private val repository: Repository
) : PresenterImpl<ArtistsView>(), ArtistsPresenter, CoroutineScope {
private val job = Job()
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.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.*
import java.util.*
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 kotlin.coroutines.CoroutineContext
/**
* Created by hemanths on 20/08/17.
*/
interface GenreDetailsView : BaseView {
fun songs(songs: ArrayList<Song>)
fun songs(songs: List<Song>)
}
interface GenreDetailsPresenter : Presenter<GenreDetailsView> {
fun loadGenreSongs(genreId: Int)
class GenreDetailsPresenterImpl @Inject constructor(
private val repository: Repository
private val repository: Repository
) : PresenterImpl<GenreDetailsView>(), GenreDetailsPresenter, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
@ -50,7 +54,6 @@ interface GenreDetailsPresenter : Presenter<GenreDetailsView> {
job.cancel()
}
override fun loadGenreSongs(genreId: Int) {
launch {
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.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.*
import java.util.*
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 kotlin.coroutines.CoroutineContext
@ -29,15 +32,17 @@ import kotlin.coroutines.CoroutineContext
* @author Hemanth S (h4h13).
*/
interface GenresView : BaseView {
fun genres(genres: ArrayList<Genre>)
fun genres(genres: List<Genre>)
}
interface GenresPresenter : Presenter<GenresView> {
fun loadGenres()
class GenresPresenterImpl @Inject constructor(
private val repository: Repository
private val repository: Repository
) : PresenterImpl<GenresView>(), GenresPresenter, CoroutineScope {
private val job = Job()
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.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 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 kotlin.coroutines.CoroutineContext
/**
* Created by hemanths on 19/08/17.
*/
interface PlaylistView : BaseView {
fun playlists(playlists: ArrayList<Playlist>)
fun playlists(playlists: List<Playlist>)
}
interface PlaylistsPresenter : Presenter<PlaylistView> {
@ -36,7 +42,7 @@ interface PlaylistsPresenter : Presenter<PlaylistView> {
fun playlists()
class PlaylistsPresenterImpl @Inject constructor(
private val repository: Repository
private val repository: Repository
) : PresenterImpl<PlaylistView>(), PlaylistsPresenter, CoroutineScope {
private val job = Job()

View file

@ -15,10 +15,17 @@
package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.mvp.*
import code.name.monkey.retromusic.model.Playlist
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 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 kotlin.coroutines.CoroutineContext
@ -26,14 +33,15 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 20/08/17.
*/
interface PlaylistSongsView : BaseView {
fun songs(songs: ArrayList<Song>)
fun songs(songs: List<Song>)
}
interface PlaylistSongsPresenter : Presenter<PlaylistSongsView> {
fun loadPlaylistSongs(playlist: Playlist)
class PlaylistSongsPresenterImpl @Inject constructor(
private val repository: Repository
private val repository: Repository
) : PresenterImpl<PlaylistSongsView>(), PlaylistSongsPresenter, CoroutineScope {
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.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 kotlinx.coroutines.*
import java.util.*
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 kotlin.coroutines.CoroutineContext
@ -27,36 +31,37 @@ import kotlin.coroutines.CoroutineContext
* Created by hemanths on 10/08/17.
*/
interface SongView {
fun songs(songs: ArrayList<Song>)
fun showEmptyView()
fun songs(songs: List<Song>)
fun showEmptyView()
}
interface SongPresenter : Presenter<SongView> {
fun loadSongs()
class SongPresenterImpl @Inject constructor(
private val repository: Repository
) : PresenterImpl<SongView>(), SongPresenter, CoroutineScope {
fun loadSongs()
class SongPresenterImpl @Inject constructor(
private val repository: Repository
) : PresenterImpl<SongView>(), SongPresenter, CoroutineScope {
private var job: Job = Job()
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun loadSongs() {
launch {
when (val songs = repository.allSongs()) {
is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) }
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
override fun loadSongs() {
launch {
when (val songs = repository.allSongs()) {
is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) }
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
}
override fun detachView() {
super.detachView()
job.cancel();
}
}
override fun detachView() {
super.detachView()
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, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
context,
attrs,
defStyleAttr,
defStyleRes
)
init {
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
@ -55,23 +60,23 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
}
}
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)
refreshBlacklistData()
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)
positiveButton(android.R.string.ok) {
dismiss()
}
neutralButton(text = getString(R.string.clear_action)) {
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(code.name.monkey.retromusic.R.string.clear_blacklist)
message(code.name.monkey.retromusic.R.string.do_you_want_to_clear_the_blacklist)
title(R.string.clear_blacklist)
message(R.string.do_you_want_to_clear_the_blacklist)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
positiveButton(code.name.monkey.retromusic.R.string.clear_action) {
positiveButton(R.string.clear_action) {
BlacklistStore.getInstance(context).clear()
refreshBlacklistData()
}
@ -81,13 +86,20 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
negativeButton(R.string.add_action) {
val dialog = BlacklistFolderChooserDialog.create()
dialog.setCallback(this@BlacklistPreferenceDialog)
dialog.show(childFragmentManager, "FOLDER_CHOOSER");
dialog.show(childFragmentManager, "FOLDER_CHOOSER")
}
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)
title(code.name.monkey.retromusic.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)))
title(R.string.remove_from_blacklist)
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) {
BlacklistStore.getInstance(context).removePath(File(text.toString()))
refreshBlacklistData()
@ -108,7 +120,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
}
override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) {
BlacklistStore.getInstance(context!!).addPath(folder);
refreshBlacklistData();
BlacklistStore.getInstance(context!!).addPath(folder)
refreshBlacklistData()
}
}

View file

@ -16,6 +16,7 @@ package code.name.monkey.retromusic.preferences
import android.app.Dialog
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.PorterDuff
import android.os.Bundle
import android.util.AttributeSet
@ -30,8 +31,12 @@ import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import code.name.monkey.appthemehelper.ThemeStore
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.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.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
@ -42,18 +47,23 @@ import com.bumptech.glide.Glide
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
override fun getDialogLayoutResource(): Int {
return mLayoutRes;
return mLayoutRes
}
init {
@ -66,11 +76,9 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
private var viewPagerPosition: Int = 0
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
@ -78,13 +86,12 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
}
override fun onDialogClosed(positiveResult: Boolean) {
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
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)
?: 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.addOnPageChangeListener(this)
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 {
fun newInstance(key: String): NowPlayingScreenPreferenceDialog {
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 {
val nowPlayingScreen = NowPlayingScreen.values()[position]
@ -148,16 +137,26 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
collection.addView(layout)
val image = layout.findViewById<ImageView>(R.id.image)
val proText = layout.findViewById<TextView>(R.id.proText)
val title = layout.findViewById<TextView>(R.id.title)
Glide.with(context).load(nowPlayingScreen.drawableResId).into(image)
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
}
override fun destroyItem(collection: ViewGroup,
position: Int,
view: Any) {
override fun destroyItem(
collection: ViewGroup,
position: Int,
view: Any
) {
collection.removeView(view as View)
}
@ -172,4 +171,19 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
override fun getPageTitle(position: Int): CharSequence? {
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 {
override suspend fun allAlbums(): Result<ArrayList<Album>> {
override suspend fun allAlbums(): Result<List<Album>> {
return try {
val albums = AlbumLoader.getAllAlbums(context)
if (albums.isNotEmpty()) {
@ -58,14 +58,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 {
val album = AlbumLoader.getAlbum(context, albumId)
if (album != null) {
Success(album)
} else {
Error(Throwable("No album"))
}
Success(album)
} catch (e: Exception) {
Error(e)
}
}
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) {
Error(e)
}
@ -289,7 +312,7 @@ class RepositoryImpl @Inject constructor(private val context: Context) : Reposit
errorMessage = "Error"
)
override suspend fun artistById(artistId: Int): Result<Artist> {
override suspend fun artistById(artistId: Long): Result<Artist> {
return try {
val artist = ArtistLoader.getArtist(context, artistId)
return Success(artist)

View file

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

View file

@ -642,7 +642,7 @@ public class MusicService extends Service implements
break;
case SHUFFLE_MODE_NONE:
this.shuffleMode = shuffleMode;
int currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
long currentSongId = Objects.requireNonNull(getCurrentSong()).getId();
playingQueue = new ArrayList<>(originalPlayingQueue);
int newPosition = 0;
if (getPlayingQueue() != null) {
@ -844,7 +844,7 @@ public class MusicService extends Service implements
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) {
if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue
.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.provider.MediaStore;
import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull;
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.ByteArrayOutputStream;
import java.io.File;
@ -37,137 +38,9 @@ import java.util.Collections;
import java.util.LinkedList;
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 {
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) {
if (mimeType == null || mimeType.equals("*/*")) {
return true;
@ -209,15 +82,95 @@ public final class FileUtil {
}
}
public static String stripExtension(String str) {
if (str == null) {
return null;
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
}
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 {
@ -234,27 +187,6 @@ public final class FileUtil {
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) {
try {
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();
Uri localUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
@ -262,7 +262,7 @@ public class MusicUtil {
}
@NonNull
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
public static Uri getMediaStoreAlbumCoverUri(long albumId) {
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
return ContentUris.withAppendedId(sArtworkUri, albumId);
}
@ -322,7 +322,7 @@ public class MusicUtil {
return songCount + " " + songString;
}
public static Uri getSongFileUri(int songId) {
public static Uri getSongFileUri(long songId) {
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
}
@ -348,7 +348,7 @@ public class MusicUtil {
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();
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);
}
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.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToAlbumOptions(@NonNull Activity activity,
int albumId,
long albumId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
@ -80,7 +80,7 @@ public class NavigationUtil {
}
public static void goToArtistOptions(@NotNull Activity activity,
int artistId,
long artistId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, ArtistDetailActivity.class);

View file

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

View file

@ -14,6 +14,12 @@
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.content.Context;
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.NowPlayingScreen;
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.AlbumSortOrder;
import code.name.monkey.retromusic.model.CategoryInfo;
import code.name.monkey.retromusic.transform.CascadingPageTransformer;
import code.name.monkey.retromusic.transform.DepthTransformation;
@ -365,6 +371,7 @@ public final class PreferenceUtil {
}
}
@NonNull
public String getAlbumDetailSongSortOrder() {
return mPreferences
.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);
}
@NonNull
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) {
@ -428,12 +436,12 @@ public final class PreferenceUtil {
}
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() {
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) {
@ -462,11 +470,12 @@ public final class PreferenceUtil {
}
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() {
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) {
@ -536,7 +545,7 @@ public final class PreferenceUtil {
}
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() {
@ -719,7 +728,7 @@ public final class PreferenceUtil {
}
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) {

View file

@ -1,9 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="35dp"/>
<stroke
android:color="@color/md_white_1000"
android:width="2dp"/>
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp" />
<stroke
android:width="2dp"
android:color="?attr/colorAccent" />
</shape>

View file

@ -2,9 +2,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/gradient_background"
android:background="?attr/colorSurface"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<LinearLayout
android:layout_width="match_parent"
@ -87,6 +87,24 @@
android:maxLines="1" />
</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
android:id="@+id/albumArtistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer"
android:layout_width="match_parent"
android:layout_height="156dp"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true">
android:layout_margin="8dp"
app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
@ -21,17 +21,6 @@
android:layout_height="match_parent"
android:scaleType="centerCrop"
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.textview.MaterialTextView

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer"
android:layout_width="match_parent"
android:layout_height="256dp"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true">
android:layout_margin="8dp"
app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
@ -21,17 +21,7 @@
android:layout_height="match_parent"
android:scaleType="centerCrop"
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.textview.MaterialTextView

View file

@ -12,8 +12,8 @@
android:id="@+id/imageContainer"
android:layout_width="match_parent"
android:layout_height="196dp"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true">
android:layout_margin="8dp"
app:cardCornerRadius="16dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
@ -22,16 +22,6 @@
android:scaleType="centerCrop"
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.textview.MaterialTextView

View file

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

View file

@ -85,6 +85,26 @@
android:maxLines="1" />
</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
android:id="@+id/albumArtistContainer"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"

View file

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

View file

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

View file

@ -5,20 +5,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="?attr/colorSurface"
android:focusable="true">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/colorBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
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" />
@ -86,5 +82,4 @@
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
</FrameLayout>
</FrameLayout>
</FrameLayout>

View file

@ -12,58 +12,63 @@
android:id="@+id/playerMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="?attr/roundSelector"
android:padding="12dp"
app:layout_constraintBottom_toBottomOf="@+id/text"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="@+id/titleContainer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_more_vert_white_24dp" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
android:layout_width="315dp"
<LinearLayout
android:id="@+id/titleContainer"
android:layout_width="0dp"
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"
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"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/progressSlider"
app:layout_constraintEnd_toStartOf="@+id/playerMenu"
app:layout_constraintStart_toEndOf="@+id/songFavourite"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:layout_editor_absoluteX="48dp"
tools:text="@tools:sample/lorem/random" />
app:layout_constraintTop_toTopOf="parent">
<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
android:id="@+id/songFavourite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:background="?attr/roundSelector"
android:padding="12dp"
app:layout_constraintBottom_toBottomOf="@+id/text"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="@+id/titleContainer"
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" />
@ -95,7 +100,7 @@
android:splitTrack="false"
app:layout_constraintEnd_toStartOf="@id/songTotalTime"
app:layout_constraintStart_toEndOf="@id/songCurrentProgress"
app:layout_constraintTop_toBottomOf="@id/text"
app:layout_constraintTop_toBottomOf="@id/titleContainer"
tools:ignore="RtlHardcoded,UnusedAttribute"
tools:progress="20" />

View file

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

View file

@ -22,16 +22,6 @@
android:scaleType="centerCrop"
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.textview.MaterialTextView

View file

@ -25,10 +25,25 @@
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/proText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
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>

View file

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

View file

@ -825,4 +825,6 @@
<string name="share_to_stories">Share to Stories</string>
<string name="drive_mode">Drive mode</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>

View file

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

View file

@ -53,13 +53,6 @@
android:layout="@layout/list_item_view_switch"
android:summary="@string/pref_summary_colored_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>
</androidx.preference.PreferenceScreen>

View file

@ -35,48 +35,6 @@ import java.lang.reflect.Field;
*/
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
@NonNull
public static Drawable createTintedDrawable(Context context,

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