package com.kabouzeid.gramophone.ui.activities;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialcab.MaterialCab;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.album.HorizontalAlbumAdapter;
import com.kabouzeid.gramophone.adapter.song.ArtistSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.glide.PhonographColoredTarget;
import com.kabouzeid.gramophone.glide.artistimage.ArtistImage;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteTranscoder;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteWrapper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.LoaderIds;
import com.kabouzeid.gramophone.interfaces.PaletteColorHolder;
import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
import com.kabouzeid.gramophone.lastfm.rest.model.LastFmArtist;
import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.misc.SimpleObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.misc.WrappedAsyncTaskLoader;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
import com.kabouzeid.gramophone.util.ArtistSignatureUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PhonographColorUtil;
import com.kabouzeid.gramophone.util.Util;
import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Be careful when changing things in this Activity!
*/
public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implements PaletteColorHolder, CabHolder, LoaderManager.LoaderCallbacks<Artist> {
public static final String TAG = ArtistDetailActivity.class.getSimpleName();
private static final int LOADER_ID = LoaderIds.ARTIST_DETAIL_ACTIVITY;
public static final String EXTRA_ARTIST_ID = "extra_artist_id";
@BindView(R.id.image)
ImageView artistImage;
@BindView(R.id.list_background)
View songListBackground;
@BindView(R.id.list)
ObservableListView songListView;
@BindView(R.id.title)
TextView artistName;
@BindView(R.id.toolbar)
Toolbar toolbar;
View songListHeader;
RecyclerView albumRecyclerView;
private MaterialCab cab;
private int headerOffset;
private int titleViewHeight;
private int artistImageViewHeight;
private int toolbarColor;
private float toolbarAlpha;
private Artist artist;
@Nullable
private Spanned biography;
private HorizontalAlbumAdapter albumAdapter;
private ArtistSongAdapter songAdapter;
private LastFMRestClient lastFMRestClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setDrawUnderStatusbar(true);
ButterKnife.bind(this);
supportPostponeEnterTransition();
lastFMRestClient = new LastFMRestClient(this);
initViews();
setUpObservableListViewParams();
setUpViews();
setUpToolbar();
getSupportLoaderManager().initLoader(LOADER_ID, getIntent().getExtras(), this);
}
@Override
protected View createContentView() {
return wrapSlidingMusicPanel(R.layout.activity_artist_detail);
}
private final SimpleObservableScrollViewCallbacks observableScrollViewCallbacks = new SimpleObservableScrollViewCallbacks() {
@Override
public void onScrollChanged(int scrollY, boolean b, boolean b2) {
scrollY += artistImageViewHeight + titleViewHeight;
float flexibleRange = artistImageViewHeight - headerOffset;
// Translate album cover
artistImage.setTranslationY(Math.max(-artistImageViewHeight, -scrollY / 2));
// Translate list background
songListBackground.setTranslationY(Math.max(0, -scrollY + artistImageViewHeight));
// Change alpha of overlay
toolbarAlpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange));
toolbar.setBackgroundColor(ColorUtil.withAlpha(toolbarColor, toolbarAlpha));
setStatusbarColor(ColorUtil.withAlpha(toolbarColor, cab != null && cab.isActive() ? 1 : toolbarAlpha));
// Translate name text
int maxTitleTranslationY = artistImageViewHeight;
int titleTranslationY = maxTitleTranslationY - scrollY;
titleTranslationY = Math.max(headerOffset, titleTranslationY);
artistName.setTranslationY(titleTranslationY);
}
};
private void setUpObservableListViewParams() {
artistImageViewHeight = getResources().getDimensionPixelSize(R.dimen.header_image_height);
toolbarColor = DialogUtils.resolveColor(this, R.attr.defaultFooterColor);
int toolbarHeight = Util.getActionBarSize(this);
titleViewHeight = getResources().getDimensionPixelSize(R.dimen.title_view_height);
headerOffset = toolbarHeight;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
headerOffset += getResources().getDimensionPixelSize(R.dimen.status_bar_padding);
}
}
private void initViews() {
songListHeader = LayoutInflater.from(this).inflate(R.layout.artist_detail_header, songListView, false);
albumRecyclerView = ButterKnife.findById(songListHeader, R.id.recycler_view);
}
private void setUpViews() {
setUpSongListView();
setUpAlbumRecyclerView();
}
private void setUpSongListView() {
setUpSongListPadding();
songListView.setScrollViewCallbacks(observableScrollViewCallbacks);
songListView.addHeaderView(songListHeader);
songAdapter = new ArtistSongAdapter(this, getArtist().getSongs(), this);
songListView.setAdapter(songAdapter);
final View contentView = getWindow().getDecorView().findViewById(android.R.id.content);
contentView.post(new Runnable() {
@Override
public void run() {
songListBackground.getLayoutParams().height = contentView.getHeight();
observableScrollViewCallbacks.onScrollChanged(-(artistImageViewHeight + titleViewHeight), false, false);
}
});
}
private void setUpSongListPadding() {
songListView.setPadding(0, artistImageViewHeight + titleViewHeight, 0, 0);
}
private void setUpAlbumRecyclerView() {
albumRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
albumAdapter = new HorizontalAlbumAdapter(this, getArtist().albums, this);
albumRecyclerView.setAdapter(albumAdapter);
albumAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
if (albumAdapter.getItemCount() == 0) finish();
}
});
}
private void reload() {
getSupportLoaderManager().restartLoader(LOADER_ID, getIntent().getExtras(), this);
}
private void loadBiography() {
lastFMRestClient.getApiService().getArtistInfo(getArtist().getName(), null).enqueue(new Callback<LastFmArtist>() {
@Override
public void onResponse(Call<LastFmArtist> call, Response<LastFmArtist> response) {
LastFmArtist lastFmArtist = response.body();
if (lastFmArtist.getArtist() != null) {
String bio = lastFmArtist.getArtist().getBio().getContent();
if (bio != null && !bio.trim().equals("")) {
biography = Html.fromHtml(bio);
return;
}
}
biography = null;
}
@Override
public void onFailure(Call<LastFmArtist> call, Throwable t) {
t.printStackTrace();
biography = null;
}
});
}
private MaterialDialog getBiographyDialog() {
return new MaterialDialog.Builder(ArtistDetailActivity.this)
.title(getArtist().getName())
.content(biography != null ? biography : "")
.positiveText(android.R.string.ok)
.build();
}
private void loadArtistImage(final boolean forceDownload) {
if (forceDownload) {
ArtistSignatureUtil.getInstance(this).updateArtistSignature(getArtist().getName());
}
Glide.with(this)
.load(new ArtistImage(getArtist().getName(), forceDownload))
.asBitmap()
.transcode(new BitmapPaletteTranscoder(this), BitmapPaletteWrapper.class)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.placeholder(R.drawable.default_artist_image)
.signature(ArtistSignatureUtil.getInstance(this).getArtistSignature(getArtist().getName()))
.dontAnimate()
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.listener(new RequestListener<ArtistImage, BitmapPaletteWrapper>() {
@Override
public boolean onException(@Nullable Exception e, ArtistImage model, Target<BitmapPaletteWrapper> target, boolean isFirstResource) {
if (forceDownload) {
Toast.makeText(ArtistDetailActivity.this, e != null ? e.getClass().getSimpleName() : "Error", Toast.LENGTH_SHORT).show();
}
return false;
}
@Override
public boolean onResourceReady(BitmapPaletteWrapper resource, ArtistImage model, Target<BitmapPaletteWrapper> target, boolean isFromMemoryCache, boolean isFirstResource) {
if (forceDownload) {
Toast.makeText(ArtistDetailActivity.this, getString(R.string.updated_artist_image), Toast.LENGTH_SHORT).show();
}
return false;
}
})
.into(new PhonographColoredTarget(artistImage) {
@Override
public void onColorReady(int color) {
setColors(color);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
reload();
}
}
@Override
public int getPaletteColor() {
return toolbarColor;
}
private void setColors(int color) {
toolbarColor = color;
artistName.setBackgroundColor(color);
artistName.setTextColor(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(color)));
setNavigationbarColor(color);
setTaskDescriptionColor(color);
}
private void setUpToolbar() {
setSupportActionBar(toolbar);
//noinspection ConstantConditions
getSupportActionBar().setTitle(null);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_artist_detail, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_equalizer:
NavigationUtil.openEqualizer(this);
return true;
case R.id.action_shuffle_artist:
MusicPlayerRemote.openAndShuffleQueue(songAdapter.getDataSet(), true);
return true;
case android.R.id.home:
super.onBackPressed();
return true;
case R.id.action_biography:
if (biography != null) {
getBiographyDialog().show();
} else {
Toast.makeText(ArtistDetailActivity.this, getResources().getString(R.string.biography_unavailable), Toast.LENGTH_SHORT).show();
}
return true;
case R.id.action_re_download_artist_image:
Toast.makeText(ArtistDetailActivity.this, getResources().getString(R.string.updating), Toast.LENGTH_SHORT).show();
loadArtistImage(true);
return true;
}
return super.onOptionsItemSelected(item);
}
@NonNull
@Override
public MaterialCab openCab(int menuRes, @NonNull final MaterialCab.Callback callback) {
if (cab != null && cab.isActive()) cab.finish();
cab = new MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
.setBackgroundColor(PhonographColorUtil.shiftBackgroundColorForLightText(getPaletteColor()))
.start(new MaterialCab.Callback() {
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
setStatusbarColor(ColorUtil.stripAlpha(toolbarColor));
return callback.onCabCreated(materialCab, menu);
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
return callback.onCabItemClicked(menuItem);
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
setStatusbarColor(ColorUtil.withAlpha(toolbarColor, toolbarAlpha));
return callback.onCabFinished(materialCab);
}
});
return cab;
}
@Override
public void onBackPressed() {
if (cab != null && cab.isActive()) cab.finish();
else {
albumRecyclerView.stopScroll();
super.onBackPressed();
}
}
@Override
public void onMediaStoreChanged() {
super.onMediaStoreChanged();
reload();
}
@Override
public void setStatusbarColor(int color) {
super.setStatusbarColor(color);
setLightStatusbar(false);
}
private void setArtist(Artist artist) {
this.artist = artist;
loadArtistImage(false);
loadBiography();
artistName.setText(artist.getName());
songAdapter.swapDataSet(artist.getSongs());
albumAdapter.swapDataSet(artist.albums);
}
private Artist getArtist() {
if (artist == null) artist = new Artist();
return artist;
}
@Override
public Loader<Artist> onCreateLoader(int id, Bundle args) {
return new AsyncArtistDataLoader(this, args.getInt(EXTRA_ARTIST_ID));
}
@Override
public void onLoadFinished(Loader<Artist> loader, Artist data) {
supportStartPostponedEnterTransition();
setArtist(data);
}
@Override
public void onLoaderReset(Loader<Artist> loader) {
this.artist = new Artist();
songAdapter.swapDataSet(artist.getSongs());
albumAdapter.swapDataSet(artist.albums);
}
private static class AsyncArtistDataLoader extends WrappedAsyncTaskLoader<Artist> {
private final int artistId;
public AsyncArtistDataLoader(Context context, int artistId) {
super(context);
this.artistId = artistId;
}
@Override
public Artist loadInBackground() {
return ArtistLoader.getArtist(getContext(), artistId);
}
}
}