Removed all blurred images. New FAB animation when opening now playing. Decreased image loader memory cache size.

This commit is contained in:
Karim Abou Zeid 2015-10-11 22:56:27 +02:00
commit 1be2260b60
9 changed files with 144 additions and 709 deletions

View file

@ -40,7 +40,6 @@ public class App extends Application {
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
.imageDownloader(new PhonographImageDownloader(this))
.taskExecutor(new PhonographExecutor())
.memoryCacheSizePercentage(30)
.build();
ImageLoader.getInstance().init(config);
L.writeLogs(false); // turns off UILs annoying LogCat output

View file

@ -1,333 +0,0 @@
package com.kabouzeid.gramophone.helper;
import android.graphics.Bitmap;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Blur using Java code.
* <p/>
* This is a compromise between Gaussian Blur and Box blur
* It creates much better looking blurs than Box Blur, but is
* 7x faster than my Gaussian Blur implementation.
* <p/>
* I called it Stack Blur because this describes best how this
* filter works internally: it creates a kind of moving stack
* of colors whilst scanning through the image. Thereby it
* just has to add one new block of color to the right side
* of the stack and remove the leftmost color. The remaining
* colors on the topmost layer of the stack are either added on
* or reduced by one, depending on if they are on the right or
* on the left side of the stack.
*
* @author Enrique López Mañas <eenriquelopez@gmail.com>
* http://www.neo-tech.es
* <p/>
* Author of the original algorithm: Mario Klingemann <mario.quasimondo.com>
* <p/>
* Based heavily on http://vitiy.info/Code/stackblur.cpp
* See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/
* @copyright: Enrique López Mañas
* @license: Apache License 2.0
*/
public class StackBlur {
static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors();
static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS);
private static final short[] stackblur_mul = {
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
};
private static final byte[] stackblur_shr = {
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
};
public static Bitmap blur(Bitmap original, float radius) {
int w = original.getWidth();
int h = original.getHeight();
int[] currentPixels = new int[w * h];
original.getPixels(currentPixels, 0, w, 0, 0, w, h);
int cores = EXECUTOR_THREADS;
ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores);
ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores);
for (int i = 0; i < cores; i++) {
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
}
try {
EXECUTOR.invokeAll(horizontal);
} catch (InterruptedException e) {
return null;
}
try {
EXECUTOR.invokeAll(vertical);
} catch (InterruptedException e) {
return null;
}
return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888);
}
private static void blurIteration(int[] src, int w, int h, int radius, int cores, int core, int step) {
int x, y, xp, yp, i;
int sp;
int stack_start;
int stack_i;
int src_i;
int dst_i;
long sum_r, sum_g, sum_b,
sum_in_r, sum_in_g, sum_in_b,
sum_out_r, sum_out_g, sum_out_b;
int wm = w - 1;
int hm = h - 1;
int div = (radius * 2) + 1;
int mul_sum = stackblur_mul[radius];
byte shr_sum = stackblur_shr[radius];
int[] stack = new int[div];
if (step == 1) {
int minY = core * h / cores;
int maxY = (core + 1) * h / cores;
for (y = minY; y < maxY; y++) {
sum_r = sum_g = sum_b =
sum_in_r = sum_in_g = sum_in_b =
sum_out_r = sum_out_g = sum_out_b = 0;
src_i = w * y; // start of line (0,y)
for (i = 0; i <= radius; i++) {
stack_i = i;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
sum_b += (src[src_i] & 0xff) * (i + 1);
sum_out_r += ((src[src_i] >>> 16) & 0xff);
sum_out_g += ((src[src_i] >>> 8) & 0xff);
sum_out_b += (src[src_i] & 0xff);
}
for (i = 1; i <= radius; i++) {
if (i <= wm) src_i += 1;
stack_i = i + radius;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
}
sp = radius;
xp = radius;
if (xp > wm) xp = wm;
src_i = xp + y * w; // img.pix_ptr(xp, y);
dst_i = y * w; // img.pix_ptr(0, y);
for (x = 0; x < w; x++) {
src[dst_i] = (int)
((src[dst_i] & 0xff000000) |
((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) |
((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) |
((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
dst_i += 1;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
stack_start = sp + div - radius;
if (stack_start >= div) stack_start -= div;
stack_i = stack_start;
sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_out_b -= (stack[stack_i] & 0xff);
if (xp < wm) {
src_i += 1;
++xp;
}
stack[stack_i] = src[src_i];
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
++sp;
if (sp >= div) sp = 0;
stack_i = sp;
sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
sum_out_b += (stack[stack_i] & 0xff);
sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_in_b -= (stack[stack_i] & 0xff);
}
}
}
// step 2
else if (step == 2) {
int minX = core * w / cores;
int maxX = (core + 1) * w / cores;
for (x = minX; x < maxX; x++) {
sum_r = sum_g = sum_b =
sum_in_r = sum_in_g = sum_in_b =
sum_out_r = sum_out_g = sum_out_b = 0;
src_i = x; // x,0
for (i = 0; i <= radius; i++) {
stack_i = i;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
sum_b += (src[src_i] & 0xff) * (i + 1);
sum_out_r += ((src[src_i] >>> 16) & 0xff);
sum_out_g += ((src[src_i] >>> 8) & 0xff);
sum_out_b += (src[src_i] & 0xff);
}
for (i = 1; i <= radius; i++) {
if (i <= hm) src_i += w; // +stride
stack_i = i + radius;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
}
sp = radius;
yp = radius;
if (yp > hm) yp = hm;
src_i = x + yp * w; // img.pix_ptr(x, yp);
dst_i = x; // img.pix_ptr(x, 0);
for (y = 0; y < h; y++) {
src[dst_i] = (int)
((src[dst_i] & 0xff000000) |
((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) |
((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) |
((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
dst_i += w;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
stack_start = sp + div - radius;
if (stack_start >= div) stack_start -= div;
stack_i = stack_start;
sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_out_b -= (stack[stack_i] & 0xff);
if (yp < hm) {
src_i += w; // stride
++yp;
}
stack[stack_i] = src[src_i];
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
++sp;
if (sp >= div) sp = 0;
stack_i = sp;
sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
sum_out_b += (stack[stack_i] & 0xff);
sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_in_b -= (stack[stack_i] & 0xff);
}
}
}
}
private static class BlurTask implements Callable<Void> {
private final int[] _src;
private final int _w;
private final int _h;
private final int _radius;
private final int _totalCores;
private final int _coreIndex;
private final int _round;
public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) {
_src = src;
_w = w;
_h = h;
_radius = radius;
_totalCores = totalCores;
_coreIndex = coreIndex;
_round = round;
}
@Override
public Void call() throws Exception {
blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round);
return null;
}
}
}

View file

@ -1,121 +0,0 @@
package com.kabouzeid.gramophone.imageloader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RSRuntimeException;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import com.kabouzeid.gramophone.BuildConfig;
import com.kabouzeid.gramophone.helper.StackBlur;
import com.kabouzeid.gramophone.util.ImageUtil;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class BlurProcessor implements BitmapProcessor {
public static final float DEFAULT_BLUR_RADIUS = 5f;
private Context context;
private final float blurRadius;
private final int sampling;
private BlurProcessor(Builder builder) {
this.context = builder.context;
this.blurRadius = builder.blurRadius;
this.sampling = builder.sampling;
}
// Something here seems to cause a memory leak... Go into LeakCanary for more details.
@Override
public Bitmap process(Bitmap bitmap) {
int sampling;
if (this.sampling == 0) {
sampling = ImageUtil.calculateInSampleSize(bitmap.getWidth(), bitmap.getHeight(), 100);
} else {
sampling = this.sampling;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int scaledWidth = width / sampling;
int scaledHeight = height / sampling;
Bitmap out = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
canvas.scale(1 / (float) sampling, 1 / (float) sampling);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
try {
final RenderScript rs = RenderScript.create(context.getApplicationContext());
final Allocation input = Allocation.createFromBitmap(rs, out, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(blurRadius);
script.setInput(input);
script.forEach(output);
output.copyTo(out);
rs.destroy();
return out;
} catch (RSRuntimeException e) {
// on some devices RenderScript.create() throws: android.support.v8.renderscript.RSRuntimeException: Error loading libRSSupport library
if (BuildConfig.DEBUG) e.printStackTrace();
return StackBlur.blur(out, blurRadius);
}
}
public static class Builder {
private Context context;
private float blurRadius = DEFAULT_BLUR_RADIUS;
private int sampling;
public Builder(@NonNull Context context) {
this.context = context;
}
/**
* @param blurRadius The radius to use. Must be between 0 and 25. Default is 5.
* @return the same Builder
*/
public Builder blurRadius(@FloatRange(from = 0.0f, to = 25.0f) float blurRadius) {
this.blurRadius = blurRadius;
return this;
}
/**
* @param sampling The inSampleSize to use. Must be a power of 2, or 1 for no down sampling or 0 for auto detect sampling. Default is 0.
* @return the same Builder
*/
public Builder sampling(int sampling) {
this.sampling = sampling;
return this;
}
public Builder fromPrototype(BlurProcessor prototype) {
context = prototype.context;
blurRadius = prototype.blurRadius;
sampling = prototype.sampling;
return this;
}
public BlurProcessor build() {
return new BlurProcessor(this);
}
}
}

View file

@ -1,7 +1,5 @@
package com.kabouzeid.gramophone.ui.activities;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
@ -11,12 +9,9 @@ import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.transition.Transition;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
@ -27,13 +22,11 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.song.AlbumSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.imageloader.BlurProcessor;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.PaletteColorHolder;
import com.kabouzeid.gramophone.loader.AlbumLoader;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.misc.SimpleObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.misc.SimpleTransitionListener;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
@ -70,8 +63,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
ObservableRecyclerView recyclerView;
@Bind(R.id.image)
ImageView albumArtImageView;
@Bind(R.id.album_art_background)
ImageView albumArtBackground;
@Bind(R.id.toolbar)
Toolbar toolbar;
@Bind(R.id.title)
@ -105,7 +96,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
setUpObservableListViewParams();
setUpToolBar();
setUpViews();
animateAlbumArtBackgroundOnEnterTransitionEnd();
}
@Override
@ -113,32 +103,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
return wrapSlidingMusicPanelAndFab(R.layout.activity_album_detail);
}
private void animateAlbumArtBackgroundOnEnterTransitionEnd() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getEnterTransition().addListener(new SimpleTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
albumArtBackground.setVisibility(View.INVISIBLE);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onTransitionEnd(Transition transition) {
int cx = (albumArtBackground.getLeft() + albumArtBackground.getRight()) / 2;
int cy = (albumArtBackground.getTop() + albumArtBackground.getBottom()) / 2;
int finalRadius = Math.max(albumArtBackground.getWidth(), albumArtBackground.getHeight());
Animator animator = ViewAnimationUtils.createCircularReveal(albumArtBackground, cx, cy, albumArtImageView.getWidth() / 2, finalRadius);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(1000);
animator.start();
albumArtBackground.setVisibility(View.VISIBLE);
}
});
}
}
private final SimpleObservableScrollViewCallbacks observableScrollViewCallbacks = new SimpleObservableScrollViewCallbacks() {
@Override
public void onScrollChanged(int scrollY, boolean b, boolean b2) {
@ -147,7 +111,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
// Translate album cover
albumArtImageView.setTranslationY(Math.max(-albumArtViewHeight, -scrollY / 2));
albumArtBackground.setTranslationY(Math.max(-albumArtViewHeight, -scrollY / 2));
// Translate list background
songsBackgroundView.setTranslationY(Math.max(0, -scrollY + albumArtViewHeight));
@ -218,7 +181,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, @Nullable FailReason failReason) {
setUpBackground("drawable://" + R.drawable.default_album_art);
setColors(ColorUtil.resolveColor(AlbumDetailActivity.this, R.attr.default_bar_color));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
@ -231,7 +193,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
onLoadingFailed(imageUri, view, null);
return;
}
setUpBackground(imageUri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
startPostponedEnterTransition();
@ -240,14 +201,6 @@ public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements
);
}
private void setUpBackground(String imageUri) {
ImageLoader.getInstance().displayImage(
imageUri,
albumArtBackground,
new DisplayImageOptions.Builder().postProcessor(new BlurProcessor.Builder(this).build()).build()
);
}
private void setColors(int vibrantColor) {
toolbarColor = vibrantColor;
albumTitleView.setBackgroundColor(vibrantColor);

View file

@ -1,7 +1,5 @@
package com.kabouzeid.gramophone.ui.activities;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
@ -13,14 +11,10 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.Spanned;
import android.transition.Transition;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
@ -33,7 +27,6 @@ import com.kabouzeid.gramophone.adapter.album.HorizontalAlbumAdapter;
import com.kabouzeid.gramophone.adapter.song.ArtistSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.imageloader.BlurProcessor;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.PaletteColorHolder;
import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
@ -42,7 +35,6 @@ import com.kabouzeid.gramophone.loader.ArtistAlbumLoader;
import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.ArtistSongLoader;
import com.kabouzeid.gramophone.misc.SimpleObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.misc.SimpleTransitionListener;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.Song;
@ -75,8 +67,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
public static final String EXTRA_ARTIST_ID = "extra_artist_id";
@Bind(R.id.artist_image_background)
ImageView artistImageBackground;
@Bind(R.id.image)
SquareIfPlaceImageView artistImage;
@Bind(R.id.list_background)
@ -122,7 +112,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
setUpObservableListViewParams();
setUpViews();
setUpToolbar();
animateAlbumArtBackgroundOnEnterTransitionEnd();
}
@Override
@ -130,32 +119,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
return wrapSlidingMusicPanelAndFab(R.layout.activity_artist_detail);
}
private void animateAlbumArtBackgroundOnEnterTransitionEnd() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getEnterTransition().addListener(new SimpleTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
artistImageBackground.setVisibility(View.INVISIBLE);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onTransitionEnd(Transition transition) {
int cx = (artistImageBackground.getLeft() + artistImageBackground.getRight()) / 2;
int cy = (artistImageBackground.getTop() + artistImageBackground.getBottom()) / 2;
int finalRadius = Math.max(artistImageBackground.getWidth(), artistImageBackground.getHeight());
Animator animator = ViewAnimationUtils.createCircularReveal(artistImageBackground, cx, cy, artistImage.getWidth() / 2, finalRadius);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(1000);
animator.start();
artistImageBackground.setVisibility(View.VISIBLE);
}
});
}
}
private final SimpleObservableScrollViewCallbacks observableScrollViewCallbacks = new SimpleObservableScrollViewCallbacks() {
@Override
public void onScrollChanged(int scrollY, boolean b, boolean b2) {
@ -164,7 +127,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
// Translate album cover
artistImage.setTranslationY(Math.max(-artistImageViewHeight, -scrollY / 2));
artistImageBackground.setTranslationY(Math.max(-artistImageViewHeight, -scrollY / 2));
// Translate list background
songListBackground.setTranslationY(Math.max(0, -scrollY + artistImageViewHeight));
@ -311,7 +273,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, @Nullable FailReason failReason) {
setUpBackground("drawable://" + R.drawable.default_artist_image);
setColors(ColorUtil.resolveColor(ArtistDetailActivity.this, R.attr.default_bar_color));
toastUpdatedArtistImageIfDownloadWasForced();
@ -324,8 +285,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
return;
}
setUpBackground(imageUri);
toastUpdatedArtistImageIfDownloadWasForced();
}
@ -356,14 +315,6 @@ public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implement
return toolbarColor;
}
private void setUpBackground(String imageUri) {
ImageLoader.getInstance().displayImage(
imageUri,
artistImageBackground,
new DisplayImageOptions.Builder().postProcessor(new BlurProcessor.Builder(this).build()).build()
);
}
private void setColors(int vibrantColor) {
toolbarColor = vibrantColor;
artistName.setBackgroundColor(vibrantColor);

View file

@ -23,7 +23,6 @@ import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
@ -50,7 +49,6 @@ import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.dialogs.SongDetailDialog;
import com.kabouzeid.gramophone.dialogs.SongShareDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.imageloader.BlurProcessor;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.misc.FloatingActionButtonProperties;
import com.kabouzeid.gramophone.misc.SimpleAnimatorListener;
@ -130,8 +128,6 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
RelativeLayout mediaControllerContainer;
@Bind(R.id.player_media_controller_container_background)
View mediaControllerContainerBackground;
@Bind(R.id.player_album_art_background)
ImageView albumArtBackground;
@Bind(R.id.player_image)
SquareIfPlaceImageView albumArt;
@Bind(R.id.player_status_bar)
@ -167,7 +163,8 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
private Song song;
private PlayPauseDrawable playPauseDrawable;
private PlayPauseDrawable miniPlayerPlayPauseDrawable;
private PlayPauseDrawable playerFabPlayPauseDrawable;
private AnimatorSet colorTransitionAnimator;
@ -310,12 +307,13 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
};
private void setUpPlayPauseButtons() {
updatePlayPauseDrawableState(false);
updatePlayPauseDrawablesStates(false);
miniPlayerPlayPauseButton.setImageDrawable(miniPlayerPlayPauseDrawable);
playerPlayPauseFab.setImageDrawable(playerFabPlayPauseDrawable);
miniPlayerPlayPauseButton.setImageDrawable(playPauseDrawable);
playerPlayPauseFab.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_keyboard_arrow_up_white_24dp));
setUpPlayerPlayPauseFabTint();
miniPlayerPlayPauseButton.getDrawable().mutate().setColorFilter(ColorUtil.resolveColor(this, android.R.attr.textColorSecondary), PorterDuff.Mode.SRC_IN);
miniPlayerPlayPauseButton.setColorFilter(ColorUtil.resolveColor(this, android.R.attr.textColorSecondary), PorterDuff.Mode.SRC_IN);
miniPlayerPlayPauseButton.setOnClickListener(playPauseButtonOnClickListener);
playerPlayPauseFab.setOnClickListener(playPauseButtonOnClickListener);
@ -381,6 +379,16 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaControllerContainer.setVisibility(View.INVISIBLE);
}
playerPlayPauseFab.post(new Runnable() {
@Override
public void run() {
playerPlayPauseFab.setPivotX(playerPlayPauseFab.getWidth() / 2);
playerPlayPauseFab.setPivotY(playerPlayPauseFab.getHeight() / 2);
}
});
playerPlayPauseFab.setScaleX(0f);
playerPlayPauseFab.setScaleY(0f);
playerPlayPauseFab.setRotation(0f);
slidingUpPanelLayout.setPanelSlideListener(this);
}
@ -398,6 +406,9 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaControllerContainer.setVisibility(View.INVISIBLE);
}
playerPlayPauseFab.setScaleX(0f);
playerPlayPauseFab.setScaleY(0f);
playerPlayPauseFab.setRotation(0f);
}
@Override
@ -406,17 +417,24 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
if (shouldColorNavigationBar()) {
super.setNavigationBarColor(lastFooterColor);
}
playerPlayPauseFab.animate()
.scaleX(1)
.scaleY(1)
.rotation(360f)
.setInterpolator(new DecelerateInterpolator())
.start();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mediaControllerContainer.getVisibility() == View.INVISIBLE) {
int cx = (playerPlayPauseFab.getLeft() + playerPlayPauseFab.getRight()) / 2;
int cy = (playerPlayPauseFab.getTop() + playerPlayPauseFab.getBottom()) / 2;
int finalRadius = Math.max(mediaControllerContainer.getWidth(), mediaControllerContainer.getHeight());
final Animator animator = ViewAnimationUtils.createCircularReveal(mediaControllerContainer, cx, cy, playerPlayPauseFab.getWidth() / 2, finalRadius);
final Animator animator = ViewAnimationUtils.createCircularReveal(mediaControllerContainer, cx, cy, 0, finalRadius);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(FAB_CIRCULAR_REVEAL_ANIMATION_TIME);
animator.start();
mediaControllerContainer.setVisibility(View.VISIBLE);
}
}
@ -469,21 +487,26 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
}
}
protected void updatePlayPauseDrawableState(boolean animate) {
if (playPauseDrawable == null) {
playPauseDrawable = new PlayPauseDrawable(this);
protected void updatePlayPauseDrawablesStates(boolean animate) {
if (miniPlayerPlayPauseDrawable == null) {
miniPlayerPlayPauseDrawable = new PlayPauseDrawable(this);
}
if (playerFabPlayPauseDrawable == null) {
playerFabPlayPauseDrawable = new PlayPauseDrawable(this);
}
if (MusicPlayerRemote.isPlaying()) {
playPauseDrawable.setPause(animate);
miniPlayerPlayPauseDrawable.setPause(animate);
playerFabPlayPauseDrawable.setPause(animate);
} else {
playPauseDrawable.setPlay(animate);
miniPlayerPlayPauseDrawable.setPlay(animate);
playerFabPlayPauseDrawable.setPlay(animate);
}
}
@Override
public void onPlayStateChanged() {
super.onPlayStateChanged();
updatePlayPauseDrawableState(true);
updatePlayPauseDrawablesStates(true);
}
protected View wrapSlidingMusicPanelAndFab(@LayoutRes int resId) {
@ -722,7 +745,6 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
}
private void setUpAlbumArtViews() {
albumArtBackground.setAlpha(0.7f);
albumArt.forceSquare(forceSquareAlbumArt);
if (opaqueStatusBar) {
if (opaqueToolBar) {
@ -838,26 +860,13 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi
public void onLoadingFailed(String imageUri, View view, @Nullable FailReason failReason) {
FadeInBitmapDisplayer.animate(view, ViewUtil.DEFAULT_COLOR_ANIMATION_DURATION);
setColors(ColorUtil.resolveColor(AbsSlidingMusicPanelActivity.this, R.attr.default_bar_color));
ImageLoader.getInstance().displayImage(
"drawable://" + R.drawable.default_album_art,
albumArtBackground,
new DisplayImageOptions.Builder().postProcessor(new BlurProcessor.Builder(AbsSlidingMusicPanelActivity.this).build()).build()
);
}
@Override
public void onLoadingComplete(String imageUri, View view, @Nullable Bitmap loadedImage) {
if (loadedImage == null) {
onLoadingFailed(imageUri, view, null);
return;
}
ImageLoader.getInstance().displayImage(
imageUri,
albumArtBackground,
new DisplayImageOptions.Builder().postProcessor(new BlurProcessor.Builder(AbsSlidingMusicPanelActivity.this).build()).build()
);
}
}
);

View file

@ -4,28 +4,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="@dimen/header_image_height"
android:background="?android:colorBackground">
<ImageView
android:id="@+id/album_art_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/default_album_art"
android:transitionName="@string/transition_album_art"
tools:ignore="ContentDescription,UnusedAttribute" />
</FrameLayout>
android:scaleType="centerCrop"
android:src="@drawable/default_album_art"
android:transitionName="@string/transition_album_art"
tools:ignore="ContentDescription,UnusedAttribute" />
<View
android:id="@+id/list_background"

View file

@ -3,29 +3,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="@dimen/header_image_height"
android:background="?android:colorBackground">
<ImageView
android:id="@+id/artist_image_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="@dimen/header_image_height"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/default_artist_image"
android:transitionName="@string/transition_artist_image"
tools:ignore="ContentDescription,UnusedAttribute" />
</FrameLayout>
android:scaleType="centerCrop"
android:src="@drawable/default_artist_image"
android:transitionName="@string/transition_artist_image"
tools:ignore="ContentDescription,UnusedAttribute" />
<View
android:id="@+id/list_background"

View file

@ -94,93 +94,106 @@
</LinearLayout>
<RelativeLayout
android:id="@+id/player_media_controller_container"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/media_controller_container_height"
tools:ignore="ContentDescription,UnusedAttribute">
android:layout_height="match_parent">
<View
android:id="@+id/player_media_controller_container_background"
<RelativeLayout
android:id="@+id/player_media_controller_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?music_controller_container_color" />
android:layout_height="@dimen/media_controller_container_height"
tools:ignore="ContentDescription,UnusedAttribute">
<android.support.v7.widget.CardView
android:id="@+id/player_playback_controller_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:visibility="gone"
app:cardBackgroundColor="?music_controller_container_color"
app:elevation="@dimen/card_elevation" />
<View
android:id="@+id/player_media_controller_container_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?music_controller_container_color" />
<ImageButton
android:id="@+id/player_prev_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_marginRight="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_toLeftOf="@+id/player_play_pause_fab"
android:layout_toStartOf="@+id/player_play_pause_fab"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_previous_white_36dp" />
<android.support.v7.widget.CardView
android:id="@+id/player_playback_controller_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:visibility="gone"
app:cardBackgroundColor="?music_controller_container_color"
app:elevation="@dimen/card_elevation" />
<ImageButton
android:id="@+id/player_next_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_marginStart="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_toEndOf="@+id/player_play_pause_fab"
android:layout_toRightOf="@+id/player_play_pause_fab"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_next_white_36dp" />
<ImageButton
android:id="@+id/player_prev_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_marginRight="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_toLeftOf="@+id/dummy_fab"
android:layout_toStartOf="@+id/dummy_fab"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_previous_white_36dp" />
<ImageButton
android:id="@+id/player_repeat_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_repeat_white_36dp" />
<ImageButton
android:id="@+id/player_next_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_marginStart="@dimen/tmp_now_playing_skip_rewind_margin"
android:layout_toEndOf="@+id/dummy_fab"
android:layout_toRightOf="@+id/dummy_fab"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_next_white_36dp" />
<ImageButton
android:id="@+id/player_shuffle_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_shuffle_white_36dp" />
<ImageButton
android:id="@+id/player_repeat_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_repeat_white_36dp" />
<ImageButton
android:id="@+id/player_shuffle_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:background="?round_selector"
android:elevation="8dp"
android:padding="22dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_shuffle_white_36dp" />
<View
android:id="@+id/dummy_fab"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_centerInParent="true"
android:visibility="invisible" />
</RelativeLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/player_play_pause_fab"
style="@style/PlayPauseFab"
android:layout_centerInParent="true" />
android:layout_gravity="center" />
</RelativeLayout>
</FrameLayout>
</LinearLayout>
@ -193,13 +206,6 @@
android:layout_above="@id/player_footer_frame"
android:background="@android:color/black">
<ImageView
android:id="@+id/player_album_art_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/player_image"
android:layout_width="match_parent"