Added Deezer for loading Artist images
This commit is contained in:
parent
e082da1dcc
commit
b43f71cc32
6 changed files with 227 additions and 55 deletions
|
@ -29,6 +29,7 @@ import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayList<Playlist>,
|
class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayList<Playlist>,
|
||||||
@param:LayoutRes protected var itemLayoutRes: Int, cabHolder: CabHolder?) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(activity, cabHolder, R.menu.menu_playlists_selection) {
|
@param:LayoutRes protected var itemLayoutRes: Int, cabHolder: CabHolder?) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(activity, cabHolder, R.menu.menu_playlists_selection) {
|
||||||
var dataSet: ArrayList<Playlist>
|
var dataSet: ArrayList<Playlist>
|
||||||
|
@ -60,6 +61,14 @@ class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayL
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun getPlaylistTitle(playlist: Playlist): String {
|
||||||
|
return playlist.name
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun getPlaylistText(playlist: Playlist): String {
|
||||||
|
return playlist.getInfoString(activity)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
|
||||||
val playlist = dataSet[position]
|
val playlist = dataSet[position]
|
||||||
|
@ -67,10 +76,10 @@ class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayL
|
||||||
holder.itemView.isActivated = isChecked(playlist)
|
holder.itemView.isActivated = isChecked(playlist)
|
||||||
|
|
||||||
if (holder.title != null) {
|
if (holder.title != null) {
|
||||||
holder.title!!.text = playlist.name
|
holder.title!!.text = getPlaylistTitle(playlist)
|
||||||
}
|
}
|
||||||
if (holder.text != null) {
|
if (holder.text != null) {
|
||||||
holder.text!!.text = String.format(Locale.getDefault(), "%d Songs", songs!!.size)
|
holder.text!!.text = getPlaylistText(playlist)
|
||||||
}
|
}
|
||||||
if (holder.image != null) {
|
if (holder.image != null) {
|
||||||
holder.image!!.setImageDrawable(getIconRes(playlist))
|
holder.image!!.setImageDrawable(getIconRes(playlist))
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package code.name.monkey.retromusic.deezer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import okhttp3.Cache
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.create
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
private const val BASE_QUERY_ARTIST = "search/artist"
|
||||||
|
private const val BASE_URL = "https://api.deezer.com/"
|
||||||
|
|
||||||
|
interface DeezerApiService {
|
||||||
|
|
||||||
|
@GET("$BASE_QUERY_ARTIST&limit=1")
|
||||||
|
fun getArtistImage(
|
||||||
|
@Query("q") artistName: String
|
||||||
|
): Call<DeezerResponse>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
operator fun invoke(client: okhttp3.Call.Factory): DeezerApiService {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.callFactory(client)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDefaultOkHttpClient(context: Context): OkHttpClient.Builder =
|
||||||
|
OkHttpClient.Builder()
|
||||||
|
.cache(createDefaultCache(context))
|
||||||
|
.addInterceptor(createCacheControlInterceptor())
|
||||||
|
|
||||||
|
private fun createDefaultCache(context: Context): Cache? {
|
||||||
|
val cacheDir = File(context.applicationContext.cacheDir.absolutePath, "/okhttp-deezer/")
|
||||||
|
if (cacheDir.mkdir() or cacheDir.isDirectory) {
|
||||||
|
return Cache(cacheDir, 1024 * 1024 * 10)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCacheControlInterceptor(): Interceptor {
|
||||||
|
return Interceptor { chain ->
|
||||||
|
val modifiedRequest = chain.request().newBuilder()
|
||||||
|
.addHeader("Cache-Control",
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"max-age=%d, max-stale=%d",
|
||||||
|
31536000, 31536000
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
chain.proceed(modifiedRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package code.name.monkey.retromusic.deezer
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class Data(
|
||||||
|
val id: String,
|
||||||
|
val link: String,
|
||||||
|
val name: String,
|
||||||
|
@SerializedName("nb_album")
|
||||||
|
val nbAlbum: Int,
|
||||||
|
@SerializedName("nb_fan")
|
||||||
|
val nbFan: Int,
|
||||||
|
val picture: String,
|
||||||
|
@SerializedName("picture_big")
|
||||||
|
val pictureBig: String,
|
||||||
|
@SerializedName("picture_medium")
|
||||||
|
val pictureMedium: String,
|
||||||
|
@SerializedName("picture_small")
|
||||||
|
val pictureSmall: String,
|
||||||
|
@SerializedName("picture_xl")
|
||||||
|
val pictureXl: String,
|
||||||
|
val radio: Boolean,
|
||||||
|
val tracklist: String,
|
||||||
|
val type: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class DeezerResponse(
|
||||||
|
val data: List<Data>,
|
||||||
|
val next: String,
|
||||||
|
val total: Int
|
||||||
|
)
|
|
@ -17,6 +17,8 @@ package code.name.monkey.retromusic.glide.artistimage
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
|
import code.name.monkey.retromusic.deezer.DeezerApiService
|
||||||
|
import code.name.monkey.retromusic.deezer.DeezerResponse
|
||||||
import code.name.monkey.retromusic.rest.LastFMRestClient
|
import code.name.monkey.retromusic.rest.LastFMRestClient
|
||||||
import code.name.monkey.retromusic.rest.model.LastFmArtist
|
import code.name.monkey.retromusic.rest.model.LastFmArtist
|
||||||
import code.name.monkey.retromusic.util.LastFMUtil
|
import code.name.monkey.retromusic.util.LastFMUtil
|
||||||
|
@ -43,12 +45,12 @@ import java.util.concurrent.TimeUnit
|
||||||
class ArtistImage(val artistName: String, val skipOkHttpCache: Boolean)
|
class ArtistImage(val artistName: String, val skipOkHttpCache: Boolean)
|
||||||
|
|
||||||
class ArtistImageFetcher(private val context: Context,
|
class ArtistImageFetcher(private val context: Context,
|
||||||
private val lastFMRestClient: LastFMRestClient,
|
private val deezerApiService: DeezerApiService,
|
||||||
private val okHttp: OkHttpClient,
|
private val okHttp: OkHttpClient,
|
||||||
private val model: ArtistImage) : DataFetcher<InputStream> {
|
private val model: ArtistImage) : DataFetcher<InputStream> {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var isCancelled: Boolean = false
|
private var isCancelled: Boolean = false
|
||||||
private var call: Call<LastFmArtist>? = null
|
private var call: Call<DeezerResponse>? = null
|
||||||
private var streamFetcher: OkHttpStreamFetcher? = null
|
private var streamFetcher: OkHttpStreamFetcher? = null
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,37 +64,30 @@ class ArtistImageFetcher(private val context: Context,
|
||||||
|
|
||||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||||
try {
|
try {
|
||||||
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context) ) {
|
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
|
||||||
call = lastFMRestClient.apiService.getArtistInfo(model.artistName, null, if (model.skipOkHttpCache) "no-cache" else null)
|
call = deezerApiService.getArtistImage(model.artistName)
|
||||||
call!!.enqueue(object : Callback<LastFmArtist> {
|
call?.enqueue(object : Callback<DeezerResponse> {
|
||||||
override fun onResponse(call: Call<LastFmArtist>, response: Response<LastFmArtist>) {
|
override fun onFailure(call: Call<DeezerResponse>, t: Throwable) {
|
||||||
|
callback.onLoadFailed(Exception(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResponse(call: Call<DeezerResponse>, response: Response<DeezerResponse>) {
|
||||||
if (isCancelled) {
|
if (isCancelled) {
|
||||||
callback.onDataReady(null)
|
callback.onDataReady(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
val lastFmArtist = response.body()
|
val deezerResponse: DeezerResponse? = response.body()
|
||||||
if (lastFmArtist == null || lastFmArtist.artist == null || lastFmArtist.artist.image == null) {
|
println(deezerResponse)
|
||||||
callback.onLoadFailed(Exception("No artist image url found"))
|
val url = deezerResponse?.data?.get(0)?.pictureXl
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val url = LastFMUtil.getLargestArtistImageUrl(lastFmArtist.artist.image)
|
|
||||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(url.trim { it <= ' ' })) {
|
|
||||||
callback.onLoadFailed(Exception("No artist image url found"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
streamFetcher = OkHttpStreamFetcher(okHttp, GlideUrl(url))
|
streamFetcher = OkHttpStreamFetcher(okHttp, GlideUrl(url))
|
||||||
streamFetcher!!.loadData(priority, callback)
|
streamFetcher?.loadData(priority, callback)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
callback.onLoadFailed(Exception("No artist image url found"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<LastFmArtist>, throwable: Throwable) {
|
|
||||||
callback.onLoadFailed(Exception(throwable))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
callback.onLoadFailed(e)
|
callback.onLoadFailed(e)
|
||||||
|
@ -108,9 +103,7 @@ class ArtistImageFetcher(private val context: Context,
|
||||||
|
|
||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
isCancelled = true
|
isCancelled = true
|
||||||
if (call != null) {
|
call?.cancel()
|
||||||
call!!.cancel()
|
|
||||||
}
|
|
||||||
if (streamFetcher != null) {
|
if (streamFetcher != null) {
|
||||||
streamFetcher!!.cancel()
|
streamFetcher!!.cancel()
|
||||||
}
|
}
|
||||||
|
@ -121,10 +114,12 @@ class ArtistImageFetcher(private val context: Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistImageLoader(private val context: Context, private val lastFMClient: LastFMRestClient, private val okhttp: OkHttpClient) : ModelLoader<ArtistImage, InputStream> {
|
class ArtistImageLoader(private val context: Context,
|
||||||
|
private val deezerApiService: DeezerApiService,
|
||||||
|
private val okhttp: OkHttpClient) : ModelLoader<ArtistImage, InputStream> {
|
||||||
|
|
||||||
override fun buildLoadData(model: ArtistImage, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
override fun buildLoadData(model: ArtistImage, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
||||||
return ModelLoader.LoadData(ObjectKey(model.artistName), ArtistImageFetcher(context, lastFMClient, okhttp, model))
|
return ModelLoader.LoadData(ObjectKey(model.artistName), ArtistImageFetcher(context, deezerApiService, okhttp, model))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handles(model: ArtistImage): Boolean {
|
override fun handles(model: ArtistImage): Boolean {
|
||||||
|
@ -132,7 +127,7 @@ class ArtistImageLoader(private val context: Context, private val lastFMClient:
|
||||||
}
|
}
|
||||||
|
|
||||||
class Factory(private val context: Context) : ModelLoaderFactory<ArtistImage, InputStream> {
|
class Factory(private val context: Context) : ModelLoaderFactory<ArtistImage, InputStream> {
|
||||||
private val lastFMClient: LastFMRestClient = LastFMRestClient(LastFMRestClient.createDefaultOkHttpClientBuilder(context)
|
private val deezerApiService: DeezerApiService = DeezerApiService.invoke(DeezerApiService.createDefaultOkHttpClient(context)
|
||||||
.connectTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
.connectTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||||
.readTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
.readTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||||
.writeTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
.writeTimeout(TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||||
|
@ -145,7 +140,7 @@ class ArtistImageLoader(private val context: Context, private val lastFMClient:
|
||||||
|
|
||||||
|
|
||||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ArtistImage, InputStream> {
|
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ArtistImage, InputStream> {
|
||||||
return ArtistImageLoader(context, lastFMClient, okHttp)
|
return ArtistImageLoader(context, deezerApiService, okHttp)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun teardown() {}
|
override fun teardown() {}
|
||||||
|
|
|
@ -14,9 +14,17 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.model;
|
package code.name.monkey.retromusic.model;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
|
||||||
|
import code.name.monkey.retromusic.util.MusicUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karim Abou Zeid (kabouzeid)
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +42,19 @@ public class Playlist implements Parcelable {
|
||||||
this.name = "";
|
this.name = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getInfoString(@NonNull Context context) {
|
||||||
|
int songCount = getSongs(context).size();
|
||||||
|
String songCountString = MusicUtil.getSongCountString(context, songCount);
|
||||||
|
return MusicUtil.buildInfoString(songCountString, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public ArrayList<Song> getSongs(Context context) {
|
||||||
|
// this default implementation covers static playlists
|
||||||
|
return PlaylistSongsLoader.INSTANCE.getPlaylistSongList(context, id).blockingFirst();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -29,6 +29,10 @@ import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
import org.jaudiotagger.audio.AudioFileIO;
|
import org.jaudiotagger.audio.AudioFileIO;
|
||||||
import org.jaudiotagger.tag.FieldKey;
|
import org.jaudiotagger.tag.FieldKey;
|
||||||
|
|
||||||
|
@ -39,14 +43,12 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.content.FileProvider;
|
|
||||||
import code.name.monkey.retromusic.R;
|
import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||||
import code.name.monkey.retromusic.loaders.PlaylistLoader;
|
import code.name.monkey.retromusic.loaders.PlaylistLoader;
|
||||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
import code.name.monkey.retromusic.loaders.SongLoader;
|
||||||
import code.name.monkey.retromusic.model.Artist;
|
import code.name.monkey.retromusic.model.Artist;
|
||||||
|
import code.name.monkey.retromusic.model.Genre;
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
import code.name.monkey.retromusic.model.Playlist;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics;
|
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics;
|
||||||
|
@ -83,6 +85,12 @@ public class MusicUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getSongCountString(@NonNull final Context context, int songCount) {
|
||||||
|
final String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
|
||||||
|
return songCount + " " + songString;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String getSongInfoString(@NonNull Song song) {
|
public static String getSongInfoString(@NonNull Song song) {
|
||||||
return MusicUtil.buildInfoString(
|
return MusicUtil.buildInfoString(
|
||||||
|
@ -91,24 +99,6 @@ public class MusicUtil {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a concatenated string from the provided arguments
|
|
||||||
* The intended purpose is to show extra annotations
|
|
||||||
* to a music library item.
|
|
||||||
* Ex: for a given album --> buildInfoString(album.artist, album.songCount)
|
|
||||||
*/
|
|
||||||
public static String buildInfoString(@NonNull final String string1, @NonNull final String string2) {
|
|
||||||
if (TextUtils.isEmpty(string1)) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return TextUtils.isEmpty(string2) ? "" : string2;
|
|
||||||
}
|
|
||||||
if (TextUtils.isEmpty(string2)) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return TextUtils.isEmpty(string1) ? "" : string1;
|
|
||||||
}
|
|
||||||
return string1 + " • " + string2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String getArtistInfoString(@NonNull final Context context,
|
public static String getArtistInfoString(@NonNull final Context context,
|
||||||
@NonNull final Artist artist) {
|
@NonNull final Artist artist) {
|
||||||
|
@ -130,7 +120,7 @@ public class MusicUtil {
|
||||||
return songCount + " " + songString;
|
return songCount + " " + songString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
/*@NonNull
|
||||||
public static String getPlaylistInfoString(@NonNull final Context context,
|
public static String getPlaylistInfoString(@NonNull final Context context,
|
||||||
@NonNull List<Song> songs) {
|
@NonNull List<Song> songs) {
|
||||||
final int songCount = songs.size();
|
final int songCount = songs.size();
|
||||||
|
@ -143,6 +133,69 @@ public class MusicUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
return songCount + " " + songString + " • " + MusicUtil.getReadableDurationString(duration);
|
return songCount + " " + songString + " • " + MusicUtil.getReadableDurationString(duration);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) {
|
||||||
|
int songCount = genre.getSongCount();
|
||||||
|
return MusicUtil.getSongCountString(context, songCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
|
||||||
|
final long duration = getTotalDuration(context, songs);
|
||||||
|
|
||||||
|
return MusicUtil.buildInfoString(
|
||||||
|
MusicUtil.getSongCountString(context, songs.size()),
|
||||||
|
MusicUtil.getReadableDurationString(duration)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a concatenated string from the provided arguments
|
||||||
|
* The intended purpose is to show extra annotations
|
||||||
|
* to a music library item.
|
||||||
|
* Ex: for a given album --> buildInfoString(album.artist, album.songCount)
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String buildInfoString(@Nullable final String string1, @Nullable final String string2) {
|
||||||
|
// Skip empty strings
|
||||||
|
if (TextUtils.isEmpty(string1)) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return TextUtils.isEmpty(string2) ? "" : string2;
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(string2)) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return TextUtils.isEmpty(string1) ? "" : string1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string1 + " • " + string2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a concatenated string from the provided arguments
|
||||||
|
* The intended purpose is to show extra annotations
|
||||||
|
* to a music library item.
|
||||||
|
* Ex: for a given album --> buildInfoString(album.artist, album.songCount)
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String buildInfoString(@Nullable final String string1, @Nullable final String string2, @NonNull final String string3) {
|
||||||
|
// Skip empty strings
|
||||||
|
if (TextUtils.isEmpty(string1)) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return TextUtils.isEmpty(string2) ? "" : string2;
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(string2)) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return TextUtils.isEmpty(string1) ? "" : string1;
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(string3)) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return TextUtils.isEmpty(string1) ? "" : string3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string1 + " • " + string2 + " • " + string3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getReadableDurationString(long songDurationMillis) {
|
public static String getReadableDurationString(long songDurationMillis) {
|
||||||
|
|
Loading…
Reference in a new issue