Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/build.gradle
This commit is contained in:
Aidan Follestad 2015-05-31 00:44:10 -05:00
commit 0cc11ae570
153 changed files with 3525 additions and 2202 deletions

View file

@ -1,14 +1,17 @@
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
mavenCentral()
}
dependencies {
classpath 'io.fabric.tools:gradle:1.18.0'
classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'com.jakewharton.hugo'
repositories {
maven { url 'https://maven.fabric.io/public' }
@ -18,14 +21,14 @@ repositories {
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
buildToolsVersion "23.0.0 rc1"
defaultConfig {
applicationId "com.kabouzeid.gramophone"
minSdkVersion 16
targetSdkVersion 22
versionCode 24
versionName "0.9.9.4b"
versionCode 29
versionName "0.9.13b DEV-2"
}
compileOptions {
@ -52,12 +55,13 @@ dependencies {
transitive = true;
}
compile 'com.android.support:appcompat-v7:22.1.1@aar'
compile 'com.android.support:recyclerview-v7:22.1.1@aar'
compile 'com.android.support:gridlayout-v7:22.1.1@aar'
compile 'com.android.support:palette-v7:22.1.1@aar'
compile 'com.android.support:support-v13:22.1.1@aar'
compile 'com.android.support:cardview-v7:22.1.1@aar'
compile 'com.android.support:appcompat-v7:22.2.0@aar'
compile 'com.android.support:recyclerview-v7:22.2.0@aar'
compile 'com.android.support:gridlayout-v7:22.2.0@aar'
compile 'com.android.support:palette-v7:22.2.0@aar'
compile 'com.android.support:support-v13:22.2.0@aar'
compile 'com.android.support:cardview-v7:22.2.0@aar'
compile 'com.android.support:design:22.2.0@aar'
compile 'com.github.ksoichiro:android-observablescrollview:1.5.1'
compile 'asia.ivity.android:drag-sort-listview:1.0'
@ -69,8 +73,7 @@ dependencies {
compile 'de.hdodenhof:circleimageview:1.3.0'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
compile 'com.afollestad:material-dialogs:0.7.5.0'
compile 'com.jpardogo.materialtabstrip:library:1.0.9'
compile 'com.afollestad:material-dialogs:0.7.4.2'
compile 'com.afollestad:material-cab:0.1.2'
compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
compile 'com.melnykov:floatingactionbutton:1.3.0'
}

View file

@ -0,0 +1,86 @@
package com.kabouzeid.gramophone.adapter;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import com.afollestad.materialcab.MaterialCab;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class AbsMultiSelectAdapter<VH extends RecyclerView.ViewHolder, I> extends RecyclerView.Adapter<VH> implements MaterialCab.Callback {
private final CabHolder cabHolder;
private MaterialCab cab;
private ArrayList<I> checked;
private int menuRes;
public AbsMultiSelectAdapter(@Nullable CabHolder cabHolder, int menuRes) {
this.cabHolder = cabHolder;
checked = new ArrayList<>();
this.menuRes = menuRes;
}
protected void toggleChecked(final int position) {
if (cabHolder != null) {
openCabIfNecessary();
I identifier = getIdentifier(position);
if (!checked.remove(identifier)) checked.add(identifier);
notifyItemChanged(position);
final int size = checked.size();
if (size <= 0) cab.finish();
else if (size == 1) cab.setTitle(checked.get(0).toString());
else if (size > 1) cab.setTitle(String.valueOf(size));
}
}
private void openCabIfNecessary() {
if (cabHolder != null) {
if (cab == null || !cab.isActive()) {
cab = cabHolder.openCab(menuRes, this);
}
}
}
private void uncheckAll() {
checked.clear();
notifyDataSetChanged();
}
protected boolean isChecked(I identifier) {
return checked.contains(identifier);
}
protected boolean isInQuickSelectMode() {
return cab != null && cab.isActive();
}
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
return true;
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
uncheckAll();
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
uncheckAll();
return true;
}
protected abstract I getIdentifier(int position);
protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList<I> selection);
}

View file

@ -1,27 +1,39 @@
package com.kabouzeid.gramophone.adapter;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.AlbumLoader;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
@ -29,15 +41,16 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> {
public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album> {
public static final String TAG = AlbumAdapter.class.getSimpleName();
private final Activity activity;
private final AppCompatActivity activity;
private boolean usePalette;
private List<Album> dataSet;
@ -53,6 +66,10 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
resetColors(holder.title, holder.artist, holder.footer);
final boolean isChecked = isChecked(album);
holder.view.setActivated(isChecked);
holder.checkMark.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE);
holder.title.setText(album.title);
holder.artist.setText(album.artistName);
@ -67,12 +84,14 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
paletteBlackAndWhite(holder.title, holder.artist, holder.footer);
if (usePalette)
paletteBlackAndWhite(holder.title, holder.artist, holder.footer);
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
applyPalette(loadedImage, holder.title, holder.artist, holder.footer);
if (usePalette)
applyPalette(loadedImage, holder.title, holder.artist, holder.footer);
}
}
);
@ -83,34 +102,90 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Album getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Album> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(getSongList(selection));
break;
}
}
private ArrayList<Song> getSongList(List<Album> albums) {
final ArrayList<Song> songs = new ArrayList<>();
for (Album album : albums) {
songs.addAll(AlbumSongLoader.getAlbumSongList(activity, album.id));
}
return songs;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final ImageView albumArt;
final TextView title;
final TextView artist;
final View footer;
final ImageView checkMark;
final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
albumArt = (ImageView) itemView.findViewById(R.id.album_art);
title = (TextView) itemView.findViewById(R.id.album_title);
artist = (TextView) itemView.findViewById(R.id.album_interpret);
footer = itemView.findViewById(R.id.footer);
itemView.setOnClickListener(this);
checkMark = (ImageView) itemView.findViewById(R.id.check_mark);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
// fixes the ripple starts at the right position
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
((FrameLayout) view.findViewById(R.id.content)).getForeground().setHotspot(motionEvent.getX(), motionEvent.getY());
return false;
}
});
}
}
@Override
public void onClick(View v) {
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt,
activity.getResources().getString(R.string.transition_album_cover)
)};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs);
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt,
activity.getResources().getString(R.string.transition_album_cover)
)};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
public AlbumAdapter(Activity activity) {
public AlbumAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
usePalette = PreferenceUtils.getInstance(activity).coloredAlbumFootersEnabled();
loadDataSet();
@ -128,9 +203,9 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
title.setTextColor(vibrantSwatch.getTitleTextColor());
artist.setTextColor(vibrantSwatch.getTitleTextColor());
ViewUtil.animateViewColor(footer, DialogUtils.resolveColor(activity, R.attr.default_bar_color), vibrantSwatch.getRgb());
title.setTextColor(Util.getOpaqueColor(vibrantSwatch.getTitleTextColor()));
artist.setTextColor(Util.getOpaqueColor(vibrantSwatch.getTitleTextColor()));
ViewUtil.animateViewColor(footer, footer.getDrawingCacheBackgroundColor(), vibrantSwatch.getRgb());
} else {
paletteBlackAndWhite(title, artist, footer);
}
@ -142,8 +217,8 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
}
private void paletteBlackAndWhite(final TextView title, final TextView artist, final View footer) {
title.setTextColor(DialogUtils.resolveColor(activity, R.attr.title_text_color));
artist.setTextColor(DialogUtils.resolveColor(activity, R.attr.caption_text_color));
title.setTextColor(Util.getOpaqueColor(DialogUtils.resolveColor(activity, R.attr.title_text_color)));
artist.setTextColor(Util.getOpaqueColor(DialogUtils.resolveColor(activity, R.attr.caption_text_color)));
int defaultBarColor = DialogUtils.resolveColor(activity, R.attr.default_bar_color);
ViewUtil.animateViewColor(footer, defaultBarColor, defaultBarColor);
}

View file

@ -1,9 +1,11 @@
package com.kabouzeid.gramophone.adapter;
import android.app.Activity;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -11,10 +13,16 @@ import android.widget.TextView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistThumbnailUrlLoader;
import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.ArtistSongLoader;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
@ -22,16 +30,18 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder> {
protected final Activity activity;
public class ArtistAdapter extends AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist> {
protected final AppCompatActivity activity;
protected List<Artist> dataSet;
public ArtistAdapter(Activity activity) {
public ArtistAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
loadDataSet();
}
@ -53,6 +63,7 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
holder.artistName.setText(artist.name);
holder.artistInfo.setText(MusicUtil.getArtistInfoString(activity, artist));
holder.artistImage.setImageResource(R.drawable.default_artist_image);
holder.view.setActivated(isChecked(artist));
LastFMArtistThumbnailUrlLoader.loadArtistThumbnailUrl(activity, artist.name, false, new LastFMArtistThumbnailUrlLoader.ArtistThumbnailUrlLoaderCallback() {
@Override
@ -73,28 +84,69 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Artist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Artist> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(getSongList(selection));
break;
}
}
private ArrayList<Song> getSongList(List<Artist> artists) {
final ArrayList<Song> songs = new ArrayList<>();
for (Artist artist : artists) {
songs.addAll(ArtistSongLoader.getArtistSongList(activity, artist.id));
}
return songs;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final TextView artistName;
final TextView artistInfo;
final ImageView artistImage;
final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
artistName = (TextView) itemView.findViewById(R.id.artist_name);
artistInfo = (TextView) itemView.findViewById(R.id.artist_info);
artistImage = (ImageView) itemView.findViewById(R.id.artist_image);
itemView.setOnClickListener(this);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
}
@Override
public void onClick(View v) {
Pair[] artistPairs = new Pair[]{
Pair.create(artistImage,
activity.getResources().getString(R.string.transition_artist_image)
)};
if (activity instanceof AbsFabActivity)
artistPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(artistPairs);
NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()).id, artistPairs);
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] artistPairs = new Pair[]{
Pair.create(artistImage,
activity.getResources().getString(R.string.transition_artist_image)
)};
if (activity instanceof AbsFabActivity)
artistPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(artistPairs);
NavigationUtil.goToArtist(activity, dataSet.get(getAdapterPosition()).id, artistPairs);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}

View file

@ -1,38 +1,59 @@
package com.kabouzeid.gramophone.adapter;
import android.app.Activity;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbumAdapter.ViewHolder> {
public class ArtistAlbumAdapter extends AbsMultiSelectAdapter<ArtistAlbumAdapter.ViewHolder, Album> {
public static final String TAG = AlbumAdapter.class.getSimpleName();
private static final int TYPE_FIRST = 1;
private static final int TYPE_MIDDLE = 2;
private static final int TYPE_LAST = 3;
private final Activity activity;
private final List<Album> dataSet;
private final AppCompatActivity activity;
private ArrayList<Album> dataSet;
private final int listMargin;
public ArtistAlbumAdapter(AppCompatActivity activity, ArrayList<Album> objects, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
dataSet = objects;
listMargin = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin);
}
public void updateDataSet(ArrayList<Album> objects) {
dataSet = objects;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(R.layout.item_grid_artist_album, parent, false);
@ -61,6 +82,7 @@ public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbumAdapter.
holder.title.setText(album.title);
holder.year.setText(String.valueOf(album.year));
holder.view.setActivated(isChecked(album));
}
@Override
@ -77,34 +99,69 @@ public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbumAdapter.
} else return TYPE_MIDDLE;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Album getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Album> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(getSongList(selection));
break;
}
}
private ArrayList<Song> getSongList(List<Album> albums) {
final ArrayList<Song> songs = new ArrayList<>();
for (Album album : albums) {
songs.addAll(AlbumSongLoader.getAlbumSongList(activity, album.id));
}
return songs;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final ImageView albumArt;
final TextView title;
final TextView year;
final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
albumArt = (ImageView) itemView.findViewById(R.id.album_art);
title = (TextView) itemView.findViewById(R.id.album_title);
year = (TextView) itemView.findViewById(R.id.album_year);
itemView.setOnClickListener(this);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
}
@Override
public void onClick(View v) {
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt,
activity.getResources().getString(R.string.transition_album_cover)
)};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs);
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt,
activity.getResources().getString(R.string.transition_album_cover)
)};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).id, albumPairs);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
public ArtistAlbumAdapter(Activity activity, List<Album> objects) {
this.activity = activity;
dataSet = objects;
listMargin = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin);
}
}

View file

@ -1,119 +0,0 @@
package com.kabouzeid.gramophone.adapter;
import android.content.Context;
import android.graphics.PorterDuff;
import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.ColorChooserDialog;
import com.kabouzeid.gramophone.model.NavigationDrawerItem;
import com.kabouzeid.gramophone.ui.fragments.NavigationDrawerFragment;
import java.util.ArrayList;
/**
* @author Aidan Follestad (afollestad)
*/
public class NavigationDrawerItemAdapter extends RecyclerView.Adapter<NavigationDrawerItemAdapter.ShortcutViewHolder> implements View.OnClickListener {
// per the Material design guidelines
@SuppressWarnings("FieldCanBeLocal")
private final int ALPHA_ACTIVATED = 255;
@SuppressWarnings("FieldCanBeLocal")
private final int ALPHA_ICON = 138;
@SuppressWarnings("FieldCanBeLocal")
private final int ALPHA_TEXT = 222;
@Override
public void onClick(View v) {
int index = (Integer) v.getTag();
if (mCallback != null)
mCallback.onItemSelected(index);
}
public static class ShortcutViewHolder extends RecyclerView.ViewHolder {
public ShortcutViewHolder(View itemView) {
super(itemView);
divider = itemView.findViewById(R.id.divider);
container = itemView.findViewById(R.id.container);
title = (TextView) itemView.findViewById(R.id.title);
icon = (ImageView) itemView.findViewById(R.id.icon);
}
final TextView title;
final ImageView icon;
final View divider;
final View container;
}
private int currentChecked = -1;
private int navIconColor;
private final ArrayList<NavigationDrawerItem> mItems;
private final Callback mCallback;
public interface Callback {
void onItemSelected(int index);
}
public NavigationDrawerItemAdapter(Context context, ArrayList<NavigationDrawerItem> objects, Callback callback) {
navIconColor = DialogUtils.resolveColor(context, R.attr.nav_drawer_icon_color);
if (DialogUtils.isColorDark(navIconColor))
navIconColor = ColorChooserDialog.shiftColorUp(navIconColor);
mItems = objects;
mCallback = callback;
}
public void setChecked(int position) {
// int oldPosition = currentChecked;
currentChecked = position;
notifyDataSetChanged();
}
@Override
public ShortcutViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_navigation_drawer, parent, false);
return new ShortcutViewHolder(view);
}
@Override
public void onBindViewHolder(ShortcutViewHolder holder, int position) {
NavigationDrawerItem item = mItems.get(position);
holder.title.setText(item.title);
holder.icon.setImageResource(item.imageRes);
holder.divider.setVisibility(position == NavigationDrawerFragment.SETTINGS_INDEX ?
View.VISIBLE : View.GONE);
final boolean selected = position == currentChecked;
final int iconColor = selected ? ThemeSingleton.get().positiveColor : navIconColor;
final int textColor = selected ? ThemeSingleton.get().positiveColor : navIconColor;
holder.title.setTextColor(textColor);
holder.title.setAlpha(selected ? ALPHA_ACTIVATED : ALPHA_TEXT);
holder.icon.setColorFilter(iconColor, PorterDuff.Mode.SRC_ATOP);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.icon.setImageAlpha(selected ? ALPHA_ACTIVATED : ALPHA_ICON);
} else {
// noinspection deprecation
holder.icon.setAlpha(selected ? ALPHA_ACTIVATED : ALPHA_ICON);
}
holder.container.setActivated(selected);
holder.container.setTag(position);
holder.container.setOnClickListener(this);
}
@Override
public int getItemCount() {
return mItems.size();
}
}

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
@ -10,25 +11,36 @@ import android.view.ViewGroup;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeletePlaylistDialog;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.PlaylistLoader;
import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHolder> {
public class PlaylistAdapter extends AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist> {
public static final String TAG = PlaylistAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected List<Playlist> dataSet;
public PlaylistAdapter(AppCompatActivity activity) {
public PlaylistAdapter(AppCompatActivity activity, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_playlists_selection);
this.activity = activity;
loadDataSet();
}
@ -45,7 +57,9 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.playlistName.setText(dataSet.get(position).name);
final Playlist playlist = dataSet.get(position);
holder.playlistName.setText(playlist.name);
holder.view.setActivated(isChecked(playlist));
}
@Override
@ -53,15 +67,46 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Playlist getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Playlist> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_playlist:
DeletePlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(getSongList(selection)).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(getSongList(selection));
break;
}
}
private ArrayList<Song> getSongList(List<Playlist> playlists) {
final ArrayList<Song> songs = new ArrayList<>();
for (Playlist playlist : playlists) {
songs.addAll(PlaylistSongLoader.getPlaylistSongList(activity, playlist.id));
}
return songs;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public final TextView playlistName;
private final View menu;
private final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
playlistName = (TextView) itemView.findViewById(R.id.playlist_name);
menu = itemView.findViewById(R.id.menu);
itemView.setOnClickListener(this);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -81,10 +126,43 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
@Override
public void onClick(View view) {
Pair[] sharedViews = null;
if (activity instanceof AbsFabActivity)
sharedViews = ((AbsFabActivity) activity).getSharedViewsWithFab(null);
NavigationUtil.goToPlaylist(activity, dataSet.get(getAdapterPosition()).id, sharedViews);
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
Pair[] sharedViews = null;
if (activity instanceof AbsFabActivity)
sharedViews = ((AbsFabActivity) activity).getSharedViewsWithFab(null);
NavigationUtil.goToPlaylist(activity, dataSet.get(getAdapterPosition()).id, sharedViews);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
App.bus.unregister(this);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
App.bus.register(this);
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.PLAYLISTS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
loadDataSet();
notifyDataSetChanged();
break;
}
}
}

View file

@ -11,6 +11,7 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
@ -20,11 +21,13 @@ import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.Collections;
@ -41,12 +44,14 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
private AppCompatActivity activity;
private List results = Collections.emptyList();
private String query;
public SearchAdapter(AppCompatActivity activity) {
this.activity = activity;
}
public void search(String query) {
this.query = query;
results = new ArrayList();
if (!query.trim().equals("")) {
List songs = SongLoader.getSongs(activity, query);
@ -224,4 +229,26 @@ public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder
}
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
App.bus.unregister(this);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
App.bus.register(this);
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.ALBUMS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
search(query);
break;
}
}
}

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.songadapter;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@ -11,8 +12,12 @@ import android.widget.PopupMenu;
import android.widget.TextView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.AbsMultiSelectAdapter;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
@ -21,17 +26,23 @@ import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AlbumSongAdapter extends RecyclerView.Adapter<AlbumSongAdapter.ViewHolder> {
public class AlbumSongAdapter extends AbsMultiSelectAdapter<AlbumSongAdapter.ViewHolder, Song> {
public static final String TAG = AlbumSongAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected final ArrayList<Song> dataSet;
protected ArrayList<Song> dataSet;
public AlbumSongAdapter(AppCompatActivity activity, ArrayList<Song> objects) {
public AlbumSongAdapter(AppCompatActivity activity, ArrayList<Song> objects, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
dataSet = objects;
}
public void updateDataSet(ArrayList<Song> objects){
dataSet = objects;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(R.layout.item_list_album_song, parent, false);
@ -47,6 +58,7 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<AlbumSongAdapter.View
holder.trackNumber.setText(trackNumberString);
holder.songTitle.setText(song.title);
holder.artistName.setText(MusicUtil.getReadableDurationString(song.duration));
holder.view.setActivated(isChecked(song));
}
@Override
@ -54,38 +66,71 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<AlbumSongAdapter.View
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Song getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Song> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(selection);
break;
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final TextView songTitle;
final TextView trackNumber;
final TextView artistName;
final ImageView overflowButton;
final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
songTitle = (TextView) itemView.findViewById(R.id.song_title);
trackNumber = (TextView) itemView.findViewById(R.id.track_number);
artistName = (TextView) itemView.findViewById(R.id.song_info);
overflowButton = (ImageView) itemView.findViewById(R.id.menu);
overflowButton.setOnClickListener(this);
itemView.setOnClickListener(new View.OnClickListener() {
view.setOnClickListener(this);
view.setOnLongClickListener(this);
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true);
PopupMenu popupMenu = new PopupMenu(activity, v);
popupMenu.inflate(R.menu.menu_item_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item);
}
});
popupMenu.show();
}
});
}
@Override
public void onClick(View v) {
PopupMenu popupMenu = new PopupMenu(activity, v);
popupMenu.inflate(R.menu.menu_item_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item);
}
});
popupMenu.show();
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition(), true);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -1,8 +1,10 @@
package com.kabouzeid.gramophone.adapter.songadapter;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -11,8 +13,13 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.afollestad.materialcab.MaterialCab;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
@ -20,22 +27,36 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.List;
import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistSongAdapter extends ArrayAdapter<Song> {
public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab.Callback {
private final CabHolder cabHolder;
private MaterialCab cab;
private ArrayList<Song> dataSet;
private ArrayList<Song> checked;
private final AppCompatActivity activity;
public ArtistSongAdapter(AppCompatActivity activity, List<Song> songs) {
public ArtistSongAdapter(AppCompatActivity activity, ArrayList<Song> songs, @Nullable CabHolder cabHolder) {
super(activity, R.layout.item_list_song, songs);
this.activity = activity;
this.cabHolder = cabHolder;
checked = new ArrayList<>();
dataSet = songs;
}
public void updateDataSet(ArrayList<Song> objects) {
dataSet = objects;
clear();
addAll(dataSet);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(final int position, View convertView, ViewGroup parent) {
final Song song = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_list_artist_song, parent, false);
@ -83,6 +104,94 @@ public class ArtistSongAdapter extends ArrayAdapter<Song> {
popupMenu.show();
}
});
convertView.setActivated(isChecked(song));
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isInQuickSelectMode()) {
toggleChecked(song);
} else {
MusicPlayerRemote.openQueue(dataSet, position, true);
}
}
});
convertView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
toggleChecked(song);
return true;
}
});
return convertView;
}
private void onMultipleItemAction(MenuItem menuItem, ArrayList<Song> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(selection);
break;
}
}
protected void toggleChecked(Song song) {
if (cabHolder != null) {
openCabIfNecessary();
if (!checked.remove(song)) checked.add(song);
notifyDataSetChanged();
final int size = checked.size();
if (size <= 0) cab.finish();
else if (size == 1) cab.setTitle(checked.get(0).toString());
else if (size > 1) cab.setTitle(String.valueOf(size));
}
}
private void openCabIfNecessary() {
if (cabHolder != null) {
if (cab == null || !cab.isActive()) {
cab = cabHolder.openCab(R.menu.menu_media_selection, this);
}
}
}
private void uncheckAll() {
checked.clear();
notifyDataSetChanged();
}
protected boolean isChecked(Song song) {
return checked.contains(song);
}
protected boolean isInQuickSelectMode() {
return cab != null && cab.isActive();
}
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
return true;
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
onMultipleItemAction(menuItem, new ArrayList<>(checked));
cab.finish();
uncheckAll();
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
uncheckAll();
return true;
}
}

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.songadapter;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
@ -12,14 +13,17 @@ import android.widget.PopupMenu;
import android.widget.TextView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.AbsMultiSelectAdapter;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteFromPlaylistDialog;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
@ -29,17 +33,23 @@ import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapter.ViewHolder> {
public class PlaylistSongAdapter extends AbsMultiSelectAdapter<PlaylistSongAdapter.ViewHolder, PlaylistSong> {
public static final String TAG = AlbumSongAdapter.class.getSimpleName();
protected final AppCompatActivity activity;
protected final ArrayList<PlaylistSong> dataSet;
protected ArrayList<PlaylistSong> dataSet;
public PlaylistSongAdapter(AppCompatActivity activity, ArrayList<PlaylistSong> objects) {
public PlaylistSongAdapter(AppCompatActivity activity, ArrayList<PlaylistSong> objects, @Nullable CabHolder cabHolder) {
super(cabHolder, R.menu.menu_playlists_songs_selection);
this.activity = activity;
dataSet = objects;
}
public void updateDataSet(ArrayList<PlaylistSong> objects) {
dataSet = objects;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(R.layout.item_list_song, parent, false);
@ -48,8 +58,9 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapte
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final Song song = dataSet.get(position);
final PlaylistSong song = dataSet.get(position);
holder.view.setActivated(isChecked(song));
holder.songTitle.setText(song.title);
holder.songInfo.setText(song.artistName);
ImageLoader.getInstance().displayImage(
@ -68,54 +79,87 @@ public class PlaylistSongAdapter extends RecyclerView.Adapter<PlaylistSongAdapte
return dataSet.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected PlaylistSong getIdentifier(int position) {
return dataSet.get(position);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<PlaylistSong> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_playlist:
DeleteFromPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_FROM_PLAYLIST");
break;
case R.id.action_add_to_playlist:
//noinspection unchecked
AddToPlaylistDialog.create((ArrayList<Song>) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
//noinspection unchecked
MusicPlayerRemote.enqueue((ArrayList<Song>) (List) selection);
break;
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final TextView songTitle;
final TextView songInfo;
final ImageView overflowButton;
final ImageView albumArt;
final View view;
public ViewHolder(View itemView) {
super(itemView);
view = itemView;
songTitle = (TextView) itemView.findViewById(R.id.song_title);
songInfo = (TextView) itemView.findViewById(R.id.song_info);
albumArt = (ImageView) itemView.findViewById(R.id.album_art);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
overflowButton = (ImageView) itemView.findViewById(R.id.menu);
overflowButton.setOnClickListener(this);
itemView.setOnClickListener(new View.OnClickListener() {
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//noinspection unchecked
MusicPlayerRemote.openQueue((ArrayList<Song>) (List) dataSet, getAdapterPosition(), true);
PopupMenu popupMenu = new PopupMenu(activity, v);
popupMenu.inflate(R.menu.menu_item_playlist_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete_from_playlist:
DeleteFromPlaylistDialog.create(dataSet.get(getAdapterPosition())).show(activity.getSupportFragmentManager(), "DELETE_FROM_PLAYLIST");
return true;
case R.id.action_go_to_album:
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt, activity.getResources().getString(R.string.transition_album_cover))
};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).albumId, albumPairs);
return true;
}
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item);
}
});
popupMenu.show();
}
});
}
@Override
public void onClick(View v) {
PopupMenu popupMenu = new PopupMenu(activity, v);
popupMenu.inflate(R.menu.menu_item_playlist_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete_from_playlist:
int position = getAdapterPosition();
PlaylistsUtil.removeFromPlaylist(activity, dataSet.remove(position));
notifyItemRemoved(position);
return true;
case R.id.action_go_to_album:
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt, activity.getResources().getString(R.string.transition_album_cover))
};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition()).albumId, albumPairs);
return true;
}
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(getAdapterPosition()), item);
}
});
popupMenu.show();
if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
//noinspection unchecked
MusicPlayerRemote.openQueue((ArrayList<Song>) (List) dataSet, getAdapterPosition(), true);
}
}
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
}
}
}

View file

@ -12,11 +12,16 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.afollestad.materialcab.MaterialCab;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.AbsMultiSelectAdapter;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
import com.kabouzeid.gramophone.helper.MenuItemClickHelper;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
@ -32,7 +37,7 @@ import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song> implements MaterialCab.Callback {
public static final String TAG = AlbumSongAdapter.class.getSimpleName();
private static final int SHUFFLE_BUTTON = 0;
@ -41,7 +46,8 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
protected final AppCompatActivity activity;
protected ArrayList<Song> dataSet;
public SongAdapter(AppCompatActivity activity) {
public SongAdapter(AppCompatActivity activity, CabHolder cabHolder) {
super(cabHolder, R.menu.menu_media_selection);
this.activity = activity;
loadDataSet();
}
@ -77,6 +83,7 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
.resetViewBeforeLoading(true)
.build()
);
holder.view.setActivated(isChecked(song));
} else {
holder.songTitle.setText(activity.getResources().getString(R.string.shuffle_all).toUpperCase());
holder.songTitle.setTextColor(ThemeSingleton.get().positiveColor);
@ -97,7 +104,27 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
return dataSet.size() + 1;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@Override
protected Song getIdentifier(int position) {
return dataSet.get(position - 1);
}
@Override
protected void onMultipleItemAction(MenuItem menuItem, ArrayList<Song> selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_from_disk:
DeleteSongsDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
break;
case R.id.action_add_to_playlist:
AddToPlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
break;
case R.id.action_add_to_current_playing:
MusicPlayerRemote.enqueue(selection);
break;
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
final TextView songTitle;
final TextView songInfo;
final ImageView overflowButton;
@ -115,45 +142,55 @@ public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
overflowButton = (ImageView) itemView.findViewById(R.id.menu);
separator = itemView.findViewById(R.id.separator);
short_separator = itemView.findViewById(R.id.short_separator);
overflowButton.setOnClickListener(this);
itemView.setOnClickListener(new View.OnClickListener() {
view.setOnClickListener(this);
view.setOnLongClickListener(this);
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getItemViewType() == SHUFFLE_BUTTON) {
MusicPlayerRemote.shuffleAllSongs(activity);
} else {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true);
}
public void onClick(View view) {
PopupMenu popupMenu = new PopupMenu(activity, view);
popupMenu.inflate(R.menu.menu_item_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final int position = getAdapterPosition() - 1;
switch (item.getItemId()) {
case R.id.action_go_to_album:
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt, activity.getResources().getString(R.string.transition_album_cover))
};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(position).albumId, albumPairs);
return true;
}
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(position), item);
}
});
popupMenu.show();
}
});
}
@Override
public void onClick(View v) {
PopupMenu popupMenu = new PopupMenu(activity, v);
popupMenu.inflate(R.menu.menu_item_song);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final int position = getAdapterPosition() - 1;
switch (item.getItemId()) {
case R.id.action_go_to_album:
Pair[] albumPairs = new Pair[]{
Pair.create(albumArt, activity.getResources().getString(R.string.transition_album_cover))
};
if (activity instanceof AbsFabActivity)
albumPairs = ((AbsFabActivity) activity).getSharedViewsWithFab(albumPairs);
NavigationUtil.goToAlbum(activity, dataSet.get(position).albumId, albumPairs);
return true;
}
return MenuItemClickHelper.handleSongMenuClick(activity, dataSet.get(position), item);
}
});
popupMenu.show();
if (getItemViewType() == SHUFFLE_BUTTON) {
MusicPlayerRemote.shuffleAllSongs(activity);
} else if (isInQuickSelectMode()) {
toggleChecked(getAdapterPosition());
} else {
MusicPlayerRemote.openQueue(dataSet, getAdapterPosition() - 1, true);
}
}
@Override
public boolean onLongClick(View view) {
if (getItemViewType() == SONG)
toggleChecked(getAdapterPosition());
return true;
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);

View file

@ -21,9 +21,8 @@ import android.widget.BaseAdapter;
import android.widget.GridView;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.views.CircleView;
import com.kabouzeid.gramophone.views.ColorView;
/**
* @author Aidan Follestad (afollestad)
@ -80,7 +79,7 @@ public class ColorChooserDialog extends DialogFragment implements View.OnClickLi
if (getArguments().getInt("title", 0) == R.string.primary_color) {
getArguments().putInt("preselect", getResources().getColor(R.color.indigo_500));
} else if (getArguments().getInt("title", 0) == R.string.accent_color) {
getArguments().putInt("preselect", getResources().getColor(R.color.pink_500));
getArguments().putInt("preselect", getResources().getColor(R.color.pink_A200));
}
invalidateGrid();
}
@ -95,7 +94,10 @@ public class ColorChooserDialog extends DialogFragment implements View.OnClickLi
mColors[i] = ta.getColor(i, 0);
ta.recycle();
mGrid = (GridView) dialog.getCustomView();
invalidateGrid();
if (mGrid != null) {
mGrid.setNumColumns(primary ? 7 : 4);
invalidateGrid();
}
return dialog;
}
@ -130,13 +132,12 @@ public class ColorChooserDialog extends DialogFragment implements View.OnClickLi
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = LayoutInflater.from(getActivity()).inflate(R.layout.griditem_color_chooser, parent, false);
final boolean dark = ThemeSingleton.get().darkTheme;
CircleView child = (CircleView) convertView;
child.setActivated(getArguments().getInt("preselect") == mColors[position]);
child.setBackgroundColor(mColors[position]);
child.setBorderColor(dark ? Color.WHITE : Color.BLACK);
child.setTag(position);
child.setOnClickListener(this);
final ColorView colorView = (ColorView) convertView;
colorView.setActivated(getArguments().getInt("preselect") == mColors[position]);
colorView.setBackgroundColor(mColors[position]);
colorView.setTag(position);
colorView.setOnClickListener(this);
Drawable selector = createSelector(mColors[position]);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -147,9 +148,9 @@ public class ColorChooserDialog extends DialogFragment implements View.OnClickLi
shiftColorDown(mColors[position])
};
ColorStateList rippleColors = new ColorStateList(states, colors);
child.setForeground(new RippleDrawable(rippleColors, selector, null));
colorView.setForeground(new RippleDrawable(rippleColors, selector, null));
} else {
child.setForeground(selector);
colorView.setForeground(selector);
}
return convertView;
}
@ -162,20 +163,14 @@ public class ColorChooserDialog extends DialogFragment implements View.OnClickLi
}
}
public static int shiftColorDown(int color) {
@SuppressWarnings("ResourceType")
private static int shiftColorDown(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.9f; // value component
return Color.HSVToColor(hsv);
}
public static int shiftColorUp(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 1.1f; // value component
return Color.HSVToColor(hsv);
}
private static int translucentColor(int color) {
final float factor = 0.7f;
int alpha = Math.round(Color.alpha(color) * factor);

View file

@ -0,0 +1,64 @@
package com.kabouzeid.gramophone.dialogs;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.text.Html;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class DeleteFromPlaylistDialog extends DialogFragment {
public static DeleteFromPlaylistDialog create(PlaylistSong song) {
ArrayList<PlaylistSong> list = new ArrayList<>();
list.add(song);
return create(list);
}
public static DeleteFromPlaylistDialog create(ArrayList<PlaylistSong> songs) {
DeleteFromPlaylistDialog dialog = new DeleteFromPlaylistDialog();
Bundle args = new Bundle();
args.putSerializable("songs", songs);
dialog.setArguments(args);
return dialog;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
final ArrayList<PlaylistSong> songs = (ArrayList<PlaylistSong>) getArguments().getSerializable("songs");
int title;
CharSequence content;
if (songs.size() > 1) {
title = R.string.delete_songs_from_playlist_title;
content = Html.fromHtml(getString(R.string.delete_x_songs_from_playlist, songs.size()));
} else {
title = R.string.delete_song_from_playlist_title;
content = Html.fromHtml(getString(R.string.delete_song_x_from_playlist, songs.get(0).title));
}
return new MaterialDialog.Builder(getActivity())
.title(title)
.content(content)
.positiveText(R.string.delete_action)
.negativeText(android.R.string.cancel)
.callback(new MaterialDialog.ButtonCallback() {
@Override
public void onPositive(MaterialDialog dialog) {
super.onPositive(dialog);
if (getActivity() == null)
return;
PlaylistsUtil.removeFromPlaylist(getActivity(), songs);
}
}).build();
}
}

View file

@ -8,17 +8,26 @@ import android.text.Html;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import java.util.ArrayList;
/**
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
* @author Karim Abou Zeid (kabouzeid)
*/
public class DeletePlaylistDialog extends DialogFragment {
public static DeletePlaylistDialog create(long playlistId) {
public static DeletePlaylistDialog create(Playlist playlist) {
ArrayList<Playlist> list = new ArrayList<>();
list.add(playlist);
return create(list);
}
public static DeletePlaylistDialog create(ArrayList<Playlist> playlists) {
DeletePlaylistDialog dialog = new DeletePlaylistDialog();
Bundle args = new Bundle();
args.putLong("playlist_id", playlistId);
args.putSerializable("playlists", playlists);
dialog.setArguments(args);
return dialog;
}
@ -26,11 +35,20 @@ public class DeletePlaylistDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
long playlistId = getArguments().getLong("playlist_id");
//noinspection unchecked
final ArrayList<Playlist> playlists = (ArrayList<Playlist>) getArguments().getSerializable("playlists");
int title;
CharSequence content;
if (playlists.size() > 1) {
title = R.string.delete_playlists_title;
content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size()));
} else {
title = R.string.delete_playlist_title;
content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name));
}
return new MaterialDialog.Builder(getActivity())
.title(R.string.delete_playlist_title)
.content(Html.fromHtml(getString(R.string.delete_playlist_x,
PlaylistsUtil.getNameForPlaylist(getActivity(), playlistId))))
.title(title)
.content(content)
.positiveText(R.string.delete_action)
.negativeText(android.R.string.cancel)
.callback(new MaterialDialog.ButtonCallback() {
@ -39,8 +57,7 @@ public class DeletePlaylistDialog extends DialogFragment {
super.onPositive(dialog);
if (getActivity() == null)
return;
long playlistId = getArguments().getLong("playlist_id");
PlaylistsUtil.deletePlaylist(getActivity(), playlistId);
PlaylistsUtil.deletePlaylists(getActivity(), playlists);
}
}).build();
}

View file

@ -36,7 +36,7 @@ public class DeleteSongsDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
ArrayList<Song> songs = (ArrayList<Song>) getArguments().getSerializable("songs");
final ArrayList<Song> songs = (ArrayList<Song>) getArguments().getSerializable("songs");
int title;
CharSequence content;
if (songs.size() > 1) {
@ -57,8 +57,6 @@ public class DeleteSongsDialog extends DialogFragment {
super.onPositive(dialog);
if (getActivity() == null)
return;
//noinspection unchecked
ArrayList<Song> songs = (ArrayList<Song>) getArguments().getSerializable("songs");
MusicUtil.deleteTracks(getActivity(), songs);
}
}).build();

View file

@ -75,7 +75,7 @@ public class MenuItemClickHelper {
RenamePlaylistDialog.create(playlist.id).show(activity.getSupportFragmentManager(), "RENAME_PLAYLIST");
return true;
case R.id.action_delete_playlist:
DeletePlaylistDialog.create(playlist.id).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
DeletePlaylistDialog.create(playlist).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
return true;
}
return false;

View file

@ -21,6 +21,7 @@ import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.util.InternalStorageUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
@ -251,6 +252,14 @@ public class MusicPlayerRemote {
}
}
public static void enqueue(List<Song> songs) {
if (musicService != null) {
musicService.addSongs(songs);
final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size());
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show();
}
}
public static void removeFromQueue(Song song) {
if (musicService != null) {
musicService.removeSong(song);

View file

@ -0,0 +1,15 @@
package com.kabouzeid.gramophone.helper.bitmapblur;
import android.graphics.Bitmap;
interface BlurProcess {
/**
* Process the given image, blurring by the supplied radius.
* If radius is 0, this will return original
*
* @param original the bitmap to be blurred
* @param radius the radius in pixels to blur the image
* @return the blurred version of the image.
*/
Bitmap blur(Bitmap original, float radius);
}

View file

@ -0,0 +1,329 @@
package com.kabouzeid.gramophone.helper.bitmapblur;
import android.graphics.Bitmap;
import java.util.ArrayList;
import java.util.concurrent.Callable;
/**
* 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
*/
class JavaBlurProcess implements BlurProcess {
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
};
@Override
public 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 = StackBlurManager.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 {
StackBlurManager.EXECUTOR.invokeAll(horizontal);
} catch (InterruptedException e) {
return null;
}
try {
StackBlurManager.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

@ -0,0 +1,89 @@
/**
* StackBlur v1.0 for Android
*
* @Author: Enrique López Mañas <eenriquelopez@gmail.com>
* http://www.lopez-manas.com
* <p/>
* Author of the original algorithm: Mario Klingemann <mario.quasimondo.com>
* <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.
* @copyright: Enrique López Mañas
* @license: Apache License 2.0
*/
package com.kabouzeid.gramophone.helper.bitmapblur;
import android.graphics.Bitmap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class StackBlurManager {
static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors();
static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS);
/**
* Original image
*/
private final Bitmap _image;
/**
* Most recent result of blurring
*/
private Bitmap _result;
/**
* Method of blurring
*/
private final BlurProcess _blurProcess;
/**
* Constructor method (basic initialization and construction of the pixel array)
*
* @param image The image that will be analyed
*/
public StackBlurManager(Bitmap image) {
_image = image;
_blurProcess = new JavaBlurProcess();
}
/**
* Process the image on the given radius. Radius must be at least 1
*
* @param radius
*/
public Bitmap process(int radius) {
_result = _blurProcess.blur(_image, radius);
return _result;
}
/**
* Returns the blurred image as a bitmap
*
* @return blurred image
*/
public Bitmap returnBlurredImage() {
return _result;
}
/**
* Returns the original image as a bitmap
*
* @return the original bitmap image
*/
public Bitmap getImage() {
return this._image;
}
}

View file

@ -0,0 +1,11 @@
package com.kabouzeid.gramophone.interfaces;
import com.afollestad.materialcab.MaterialCab;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public interface CabHolder {
MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback);
}

View file

@ -27,9 +27,8 @@ public class AlbumLoader {
final int artistId = cursor.getInt(3);
final int songCount = cursor.getInt(4);
final int year = cursor.getInt(5);
final String albumArtPath = cursor.getString(6);
final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath);
final Album album = new Album(id, albumName, artist, artistId, songCount, year);
albums.add(album);
} while (cursor.moveToNext());
}
@ -58,8 +57,6 @@ public class AlbumLoader {
MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS,
/* 5 */
MediaStore.Audio.AlbumColumns.FIRST_YEAR,
/* 6 */
MediaStore.Audio.AlbumColumns.ALBUM_ART
}, selection, values, PreferenceUtils.getInstance(context).getAlbumSortOrder());
}
@ -73,9 +70,8 @@ public class AlbumLoader {
final int artistId = cursor.getInt(3);
final int songCount = cursor.getInt(4);
final int year = cursor.getInt(5);
final String albumArtPath = cursor.getString(6);
album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath);
album = new Album(id, albumName, artist, artistId, songCount, year);
}
if (cursor != null) {
@ -95,9 +91,8 @@ public class AlbumLoader {
final int artistId = cursor.getInt(3);
final int songCount = cursor.getInt(4);
final int year = cursor.getInt(5);
final String albumArtPath = cursor.getString(6);
final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath);
final Album album = new Album(id, albumName, artist, artistId, songCount, year);
albums.add(album);
} while (cursor.moveToNext());
}

View file

@ -27,9 +27,8 @@ public class AlbumSongLoader {
final long duration = cursor.getLong(4);
final int trackNumber = cursor.getInt(5);
final int artistId = cursor.getInt(6);
final long dateModified = cursor.getInt(7);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber);
songs.add(song);
} while (cursor.moveToNext());
}
@ -54,9 +53,7 @@ public class AlbumSongLoader {
/* 5 */
MediaStore.Audio.AudioColumns.TRACK,
/* 6 */
MediaStore.Audio.AudioColumns.ARTIST_ID,
/* 7 */
MediaStore.Audio.AudioColumns.DATE_MODIFIED
MediaStore.Audio.AudioColumns.ARTIST_ID
}, (MediaStore.Audio.AudioColumns.IS_MUSIC + "=1") + " AND " +
MediaStore.Audio.AudioColumns.TITLE + " != ''" + " AND " +
MediaStore.Audio.AudioColumns.ALBUM_ID + "=" + albumId, null,

View file

@ -9,16 +9,15 @@ import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistAlbumLoader {
public static List<Album> getArtistAlbumList(final Context context, final int artistId) {
public static ArrayList<Album> getArtistAlbumList(final Context context, final int artistId) {
Cursor cursor = makeArtistAlbumCursor(context, artistId);
List<Album> albums = new ArrayList<>();
ArrayList<Album> albums = new ArrayList<>();
if (cursor != null && cursor.moveToFirst()) {
do {
final int id = cursor.getInt(0);
@ -26,9 +25,8 @@ public class ArtistAlbumLoader {
final String artist = cursor.getString(2);
final int songCount = cursor.getInt(3);
final int year = cursor.getInt(4);
final String albumArtPath = cursor.getString(5);
final Album album = new Album(id, albumName, artist, artistId, songCount, year, albumArtPath);
final Album album = new Album(id, albumName, artist, artistId, songCount, year);
albums.add(album);
} while (cursor.moveToNext());
}
@ -51,8 +49,6 @@ public class ArtistAlbumLoader {
MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS,
/* 4 */
MediaStore.Audio.AlbumColumns.FIRST_YEAR,
/* 5 */
MediaStore.Audio.AlbumColumns.ALBUM_ART
}, null, null, PreferenceUtils.getInstance(context).getArtistAlbumSortOrder());
}
}

View file

@ -27,9 +27,8 @@ public class ArtistSongLoader {
final long duration = cursor.getLong(4);
final int trackNumber = cursor.getInt(5);
final int albumId = cursor.getInt(6);
final long dateModified = cursor.getInt(7);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber);
songs.add(song);
} while (cursor.moveToNext());
}
@ -54,9 +53,7 @@ public class ArtistSongLoader {
/* 5 */
MediaStore.Audio.AudioColumns.TRACK,
/* 6 */
MediaStore.Audio.AudioColumns.ALBUM_ID,
/* 7 */
MediaStore.Audio.AudioColumns.DATE_MODIFIED
MediaStore.Audio.AudioColumns.ALBUM_ID
}, (MediaStore.Audio.AudioColumns.IS_MUSIC + "=1") + " AND " +
MediaStore.Audio.AudioColumns.TITLE + " != ''" + " AND " +
MediaStore.Audio.AudioColumns.ARTIST_ID + "=" + artistId, null,

View file

@ -26,9 +26,8 @@ public class PlaylistSongLoader {
final int albumId = cursor.getInt(6);
final int artistId = cursor.getInt(7);
final int idInPlaylist = cursor.getInt(8);
final long dateModified = cursor.getInt(9);
final PlaylistSong song = new PlaylistSong(id, albumId, artistId, songName, artist, album, duration, trackNumber, playlistID, idInPlaylist, dateModified);
final PlaylistSong song = new PlaylistSong(id, albumId, artistId, songName, artist, album, duration, trackNumber, playlistID, idInPlaylist);
songs.add(song);
} while (cursor.moveToNext());
@ -60,9 +59,7 @@ public class PlaylistSongLoader {
/* 7 */
AudioColumns.ARTIST_ID,
/* 8 */
MediaStore.Audio.Playlists.Members._ID,
/* 9 */
MediaStore.Audio.AudioColumns.DATE_MODIFIED
MediaStore.Audio.Playlists.Members._ID
}, (AudioColumns.IS_MUSIC + "=1") + " AND " + AudioColumns.TITLE + " != ''", null,
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
}

View file

@ -30,9 +30,8 @@ public class SongLoader {
final int trackNumber = cursor.getInt(5);
final int artistId = cursor.getInt(6);
final int albumId = cursor.getInt(7);
final long dateModified = cursor.getInt(8);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber);
songs.add(song);
} while (cursor.moveToNext());
}
@ -68,9 +67,7 @@ public class SongLoader {
/* 6 */
MediaStore.Audio.AudioColumns.ARTIST_ID,
/* 7 */
MediaStore.Audio.AudioColumns.ALBUM_ID,
/* 8 */
MediaStore.Audio.AudioColumns.DATE_MODIFIED
MediaStore.Audio.AudioColumns.ALBUM_ID
}, finalSelection, values, PreferenceUtils.getInstance(context).getSongSortOrder());
}
@ -87,9 +84,8 @@ public class SongLoader {
final int trackNumber = cursor.getInt(5);
final int artistId = cursor.getInt(6);
final int albumId = cursor.getInt(7);
final long dateModified = cursor.getInt(8);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified);
final Song song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber);
songs.add(song);
} while (cursor.moveToNext());
}
@ -111,8 +107,7 @@ public class SongLoader {
final int trackNumber = cursor.getInt(5);
final int artistId = cursor.getInt(6);
final int albumId = cursor.getInt(7);
final long dateModified = cursor.getInt(8);
song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, dateModified);
song = new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber);
}
if (cursor != null) {
cursor.close();

View file

@ -362,6 +362,11 @@ public class DragSortRecycler extends RecyclerView.ItemDecoration implements Rec
rv.invalidateItemDecorations();// Redraw
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
private void setIsDragging(final boolean dragging) {
if (dragging != isDragging) {
isDragging = dragging;

View file

@ -1,5 +1,7 @@
package com.kabouzeid.gramophone.model;
import android.text.TextUtils;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
@ -11,17 +13,15 @@ public class Album {
public final String artistName;
public final int songCount;
public final int year;
public final String albumArtPath; //used as cache key
public Album(final int id, final String title, final String artistName, final int artistId,
final int songNumber, final int albumYear, final String albumArtPath) {
final int songNumber, final int albumYear) {
this.id = id;
this.title = title;
this.artistName = artistName;
this.artistId = artistId;
songCount = songNumber;
year = albumYear;
this.albumArtPath = albumArtPath != null ? albumArtPath : "";
}
public Album() {
@ -31,6 +31,49 @@ public class Album {
this.artistId = -1;
songCount = -1;
year = -1;
this.albumArtPath = "";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + (title == null ? 0 : title.hashCode());
result = prime * result + (artistName == null ? 0 : artistName.hashCode());
result = prime * result + songCount;
result = prime * result + year;
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Album other = (Album) obj;
if (id != other.id) {
return false;
}
if (!TextUtils.equals(title, other.title)) {
return false;
}
if (!TextUtils.equals(artistName, other.artistName)) {
return false;
}
if (songCount != other.songCount) {
return false;
}
return year == other.year;
}
@Override
public String toString() {
return title;
}
}

View file

@ -1,5 +1,7 @@
package com.kabouzeid.gramophone.model;
import android.text.TextUtils;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
@ -22,4 +24,44 @@ public class Artist {
songCount = -1;
albumCount = -1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + albumCount;
result = prime * result + id;
result = prime * result + (name == null ? 0 : name.hashCode());
result = prime * result + songCount;
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Artist other = (Artist) obj;
if (albumCount != other.albumCount) {
return false;
}
if (id != other.id) {
return false;
}
if (!TextUtils.equals(name, other.name)) {
return false;
}
return songCount == other.songCount;
}
@Override
public String toString() {
return name;
}
}

View file

@ -1,6 +1,16 @@
package com.kabouzeid.gramophone.model;
public class Playlist {
import android.text.TextUtils;
import java.io.Serializable;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class Playlist implements Serializable {
private static final long serialVersionUID = 3013703495354856981L;
public final int id;
public final String name;
@ -13,4 +23,36 @@ public class Playlist {
this.id = -1;
this.name = "";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + (name == null ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Playlist other = (Playlist) obj;
if (id != other.id) {
return false;
}
return TextUtils.equals(name, other.name);
}
@Override
public String toString() {
return name;
}
}

View file

@ -8,8 +8,8 @@ public class PlaylistSong extends Song {
public final int idInPlayList;
public PlaylistSong(final int id, final int albumId, final int artistId, final String title, final String artistName,
final String albumName, final long duration, final int trackNumber, final int playlistId, final int idInPlayList, final long dateModified) {
super(id, albumId, artistId, title, artistName, albumName, duration, trackNumber, dateModified);
final String albumName, final long duration, final int trackNumber, final int playlistId, final int idInPlayList) {
super(id, albumId, artistId, title, artistName, albumName, duration, trackNumber);
this.playlistId = playlistId;
this.idInPlayList = idInPlayList;
}
@ -19,4 +19,22 @@ public class PlaylistSong extends Song {
playlistId = -1;
idInPlayList = -1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + playlistId;
result = prime * result + idInPlayList;
return result;
}
@Override
public boolean equals(final Object obj) {
if (super.equals(obj)) {
final PlaylistSong other = (PlaylistSong) obj;
return playlistId == other.playlistId && idInPlayList == other.idInPlayList;
}
return false;
}
}

View file

@ -1,5 +1,7 @@
package com.kabouzeid.gramophone.model;
import android.text.TextUtils;
import java.io.Serializable;
/**
@ -17,10 +19,9 @@ public class Song implements Serializable {
public final String albumName;
public final long duration;
public final int trackNumber;
public final long dateModified; //used as cache key
public Song(final int id, final int albumId, final int artistId, final String title, final String artistName,
final String albumName, final long duration, final int trackNumber, final long dateModified) {
final String albumName, final long duration, final int trackNumber) {
this.id = id;
this.albumId = albumId;
this.artistId = artistId;
@ -29,7 +30,6 @@ public class Song implements Serializable {
this.albumName = albumName;
this.duration = duration;
this.trackNumber = trackNumber;
this.dateModified = dateModified;
}
public Song() {
@ -41,6 +41,49 @@ public class Song implements Serializable {
this.albumName = "";
this.duration = -1;
this.trackNumber = -1;
this.dateModified = -1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (albumName == null ? 0 : albumName.hashCode());
result = prime * result + (artistName == null ? 0 : artistName.hashCode());
result = prime * result + (int) duration;
result = prime * result + id;
result = prime * result + (title == null ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Song other = (Song) obj;
if (id != other.id) {
return false;
}
if (!TextUtils.equals(albumName, other.albumName)) {
return false;
}
if (!TextUtils.equals(artistName, other.artistName)) {
return false;
}
if (duration != other.duration) {
return false;
}
return TextUtils.equals(title, other.title);
}
@Override
public String toString() {
return title;
}
}

View file

@ -13,8 +13,6 @@ public class UIPreferenceChangedEvent {
public static final int COLORED_NAVIGATION_BAR_CURRENT_PLAYING_CHANGED = 6;
public static final int COLORED_NAVIGATION_BAR_CHANGED = 10;
public static final int COLORED_NAVIGATION_BAR_OTHER_SCREENS_CHANGED = 7;
public static final int PLAYBACK_CONTROLLER_CARD_CHANGED = 8;
public static final int TOOLBAR_TRANSPARENT_CHANGED = 9;
private final int action;
private final Object value;

View file

@ -7,7 +7,7 @@ import android.util.AttributeSet;
import android.view.View;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.views.CircleView;
import com.kabouzeid.gramophone.views.ColorView;
public class ColorChooserPreference extends Preference {
@ -43,11 +43,10 @@ public class ColorChooserPreference extends Preference {
private void invalidateColor() {
if (mView != null) {
CircleView circle = (CircleView) mView.findViewById(R.id.circle);
ColorView circle = (ColorView) mView.findViewById(R.id.circle);
if (this.color != 0) {
circle.setVisibility(View.VISIBLE);
circle.setBackgroundColor(color);
circle.setBorderColor(border);
} else {
circle.setVisibility(View.GONE);
}

View file

@ -42,6 +42,7 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MusicService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener {
public static final String ACTION_TOGGLE_PLAYBACK = "com.kabouzeid.gramophone.action.TOGGLE_PLAYBACK";
@ -552,6 +553,18 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe
saveState();
}
public void addSongs(int position, List<Song> songs) {
playingQueue.addAll(position, songs);
originalPlayingQueue.addAll(position, songs);
saveState();
}
public void addSongs(List<Song> songs) {
playingQueue.addAll(songs);
originalPlayingQueue.addAll(songs);
saveState();
}
public void removeSong(int position) {
if (getShuffleMode() == SHUFFLE_MODE_NONE) {
playingQueue.remove(position);
@ -796,7 +809,7 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe
//to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch
final Intent intent = new Intent(what);
final int position = getPosition();
if(position >= 0) {
if (position >= 0 && !playingQueue.isEmpty()) {
final Song currentSong = playingQueue.get(position);
intent.putExtra("id", currentSong.id);
intent.putExtra("artist", currentSong.artistName);

View file

@ -1,8 +1,9 @@
package com.kabouzeid.gramophone.ui.activities;
import android.annotation.TargetApi;
import android.animation.Animator;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
@ -10,24 +11,32 @@ import android.support.v4.util.Pair;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.GridLayoutManager;
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;
import com.afollestad.materialcab.MaterialCab;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.songadapter.AlbumSongAdapter;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager;
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.AppKeys;
import com.kabouzeid.gramophone.misc.SmallObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.misc.SmallTransitionListener;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
@ -51,22 +60,27 @@ import java.util.ArrayList;
* <p/>
* Should be kinda stable ONLY AS IT IS!!!
*/
public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorHolder {
public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorHolder, CabHolder {
public static final String TAG = AlbumDetailActivity.class.getSimpleName();
private static final int TAG_EDITOR_REQUEST = 2001;
private Album album;
private ObservableRecyclerView recyclerView;
private View statusBar;
private AlbumSongAdapter adapter;
private ArrayList<Song> songs;
private ImageView albumArtImageView;
private ImageView albumArtBackground;
private View songsBackgroundView;
private TextView albumTitleView;
private Toolbar toolbar;
private MaterialCab cab;
private int headerOffset;
private int titleViewHeight;
private int albumArtViewHeight;
private int toolbarColor;
private float toolbarAlpha;
private int bottomOffset;
private final SmallObservableScrollViewCallbacks observableScrollViewCallbacks = new SmallObservableScrollViewCallbacks() {
@Override
@ -82,9 +96,9 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
ViewHelper.setTranslationY(songsBackgroundView, Math.max(0, -scrollY + albumArtViewHeight));
// Change alpha of overlay
float alpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange));
ViewUtil.setBackgroundAlpha(toolbar, alpha, toolbarColor);
ViewUtil.setBackgroundAlpha(statusBar, alpha, toolbarColor);
toolbarAlpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange));
ViewUtil.setBackgroundAlpha(toolbar, toolbarAlpha, toolbarColor);
setStatusBarColor(Util.getColorWithAlpha(cab != null && cab.isActive() ? 1 : toolbarAlpha, toolbarColor));
// Translate name text
int maxTitleTranslationY = albumArtViewHeight;
@ -92,26 +106,21 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
titleTranslationY = Math.max(headerOffset, titleTranslationY);
ViewHelper.setTranslationY(albumTitleView, titleTranslationY);
// Translate FAB
int fabTranslationY = titleTranslationY + titleViewHeight - (getFab().getHeight() / 2);
ViewHelper.setTranslationY(getFab(), fabTranslationY);
}
};
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(true);
setStatusBarTransparent();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_album_detail);
App.bus.register(this);
if (Util.isAtLeastLollipop()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
postponeEnterTransition();
if (PreferenceUtils.getInstance(this).coloredNavigationBarAlbumEnabled())
getWindow().setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
}
Bundle intentExtras = getIntent().getExtras();
@ -128,16 +137,29 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
setUpObservableListViewParams();
setUpToolBar();
setUpViews();
}
@Override
protected boolean shouldColorStatusBar() {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getEnterTransition().addListener(new SmallTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
albumArtBackground.setVisibility(View.INVISIBLE);
}
@Override
protected boolean shouldColorNavBar() {
return false;
@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);
}
});
}
}
@Override
@ -147,21 +169,23 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
private void initViews() {
albumArtImageView = (ImageView) findViewById(R.id.album_art);
albumArtBackground = (ImageView) findViewById(R.id.album_art_background);
toolbar = (Toolbar) findViewById(R.id.toolbar);
recyclerView = (ObservableRecyclerView) findViewById(R.id.list);
albumTitleView = (TextView) findViewById(R.id.album_title);
songsBackgroundView = findViewById(R.id.list_background);
statusBar = findViewById(R.id.statusBar);
// statusBar = findViewById(R.id.status_bar);
}
private void setUpObservableListViewParams() {
bottomOffset = getResources().getDimensionPixelSize(R.dimen.bottom_offset_fab_activity);
albumArtViewHeight = getResources().getDimensionPixelSize(R.dimen.header_image_height);
toolbarColor = DialogUtils.resolveColor(this, R.attr.default_bar_color);
int toolbarHeight = Util.getActionBarSize(this);
titleViewHeight = getResources().getDimensionPixelSize(R.dimen.title_view_height);
headerOffset = toolbarHeight;
if (Util.isAtLeastKitKat())
headerOffset += getResources().getDimensionPixelSize(R.dimen.statusMargin);
headerOffset += getResources().getDimensionPixelSize(R.dimen.status_bar_padding);
}
private void setUpViews() {
@ -181,18 +205,22 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
.resetViewBeforeLoading(true)
.build(),
new SimpleImageLoadingListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
applyPalette(null);
if (Util.isAtLeastLollipop()) startPostponedEnterTransition();
albumArtBackground.setImageBitmap(new StackBlurManager(BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art)).process(10));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
startPostponedEnterTransition();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
applyPalette(loadedImage);
if (Util.isAtLeastLollipop()) startPostponedEnterTransition();
albumArtBackground.setImageBitmap(new StackBlurManager(loadedImage).process(10));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
startPostponedEnterTransition();
}
}
);
@ -202,16 +230,16 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
albumTitleView.setBackgroundColor(toolbarColor);
albumTitleView.setTextColor(vibrantSwatch.getTitleTextColor());
albumTitleView.setTextColor(Util.getOpaqueColor(vibrantSwatch.getTitleTextColor()));
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(AlbumDetailActivity.this).coloredNavigationBarAlbumEnabled())
getWindow().setNavigationBarColor(toolbarColor);
setNavigationBarColor(toolbarColor);
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
@ -223,7 +251,7 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void resetColors() {
int titleTextColor = DialogUtils.resolveColor(this, R.attr.title_text_color);
int defaultBarColor = DialogUtils.resolveColor(this, R.attr.default_bar_color);
@ -233,7 +261,7 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
albumTitleView.setTextColor(titleTextColor);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
notifyTaskColorChange(toolbarColor);
}
@ -248,18 +276,18 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
return toolbarColor;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setNavigationBarColored(boolean colored) {
if (colored) {
if (Util.isAtLeastLollipop()) getWindow().setNavigationBarColor(toolbarColor);
setNavigationBarColor(toolbarColor);
} else {
if (Util.isAtLeastLollipop()) getWindow().setNavigationBarColor(Color.BLACK);
setNavigationBarColor(Color.BLACK);
}
}
private void setUpListView() {
recyclerView.setScrollViewCallbacks(observableScrollViewCallbacks);
recyclerView.setPadding(0, albumArtViewHeight + titleViewHeight, 0, 0);
recyclerView.setPadding(0, albumArtViewHeight + titleViewHeight, 0, bottomOffset);
final View contentView = getWindow().getDecorView().findViewById(android.R.id.content);
contentView.post(new Runnable() {
@Override
@ -279,10 +307,10 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
}
private void setUpSongsAdapter() {
final ArrayList<Song> songs = AlbumSongLoader.getAlbumSongList(this, album.id);
final AlbumSongAdapter albumSongAdapter = new AlbumSongAdapter(this, songs);
songs = AlbumSongLoader.getAlbumSongList(this, album.id);
adapter = new AlbumSongAdapter(this, songs, this);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
recyclerView.setAdapter(albumSongAdapter);
recyclerView.setAdapter(adapter);
}
@Override
@ -346,6 +374,19 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
}
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.SONGS_CHANGED:
case DataBaseChangedEvent.ALBUMS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
songs = AlbumSongLoader.getAlbumSongList(this, album.id);
adapter.updateDataSet(songs);
if (songs.size() < 1) finish();
break;
}
}
@Subscribe
public void onUIPreferenceChanged(UIPreferenceChangedEvent event) {
switch (event.getAction()) {
@ -360,4 +401,37 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
super.onDestroy();
App.bus.unregister(this);
}
@Override
public MaterialCab openCab(int menuRes, final MaterialCab.Callback callback) {
if (cab != null && cab.isActive()) cab.finish();
cab = new MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setBackgroundColor(getPaletteColor())
.start(new MaterialCab.Callback() {
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
setStatusBarColor(Util.getOpaqueColor(toolbarColor));
return callback.onCabCreated(materialCab, menu);
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
return callback.onCabItemClicked(menuItem);
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
setStatusBarColor(Util.getColorWithAlpha(toolbarAlpha, toolbarColor));
return callback.onCabFinished(materialCab);
}
});
return cab;
}
@Override
public void onBackPressed() {
if (cab != null && cab.isActive()) cab.finish();
else super.onBackPressed();
}
}

View file

@ -1,8 +1,9 @@
package com.kabouzeid.gramophone.ui.activities;
import android.annotation.TargetApi;
import android.animation.Animator;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
@ -17,11 +18,13 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.view.ViewAnimationUtils;
import android.view.animation.DecelerateInterpolator;
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.github.ksoichiro.android.observablescrollview.ObservableListView;
@ -30,6 +33,8 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.ArtistAlbumAdapter;
import com.kabouzeid.gramophone.adapter.songadapter.ArtistSongAdapter;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.PaletteColorHolder;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistBiographyLoader;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistImageUrlLoader;
@ -38,8 +43,10 @@ import com.kabouzeid.gramophone.loader.ArtistLoader;
import com.kabouzeid.gramophone.loader.ArtistSongLoader;
import com.kabouzeid.gramophone.misc.AppKeys;
import com.kabouzeid.gramophone.misc.SmallObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.misc.SmallTransitionListener;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
@ -55,33 +62,38 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
/**
* A lot of hackery is done in this activity. Changing things may will brake the whole activity.
* <p/>
* Should be kinda stable ONLY AS IT IS!!!
*/
public class ArtistDetailActivity extends AbsFabActivity implements PaletteColorHolder {
public class ArtistDetailActivity extends AbsFabActivity implements PaletteColorHolder, CabHolder {
public static final String TAG = ArtistDetailActivity.class.getSimpleName();
private Artist artist;
private ObservableListView songListView;
private View statusBar;
private ImageView artistImage;
private ImageView artistImageBackground;
private View songsBackgroundView;
private TextView artistNameTv;
private Toolbar toolbar;
private MaterialCab cab;
private int headerOffset;
private int titleViewHeight;
private int artistImageViewHeight;
private int toolbarColor;
private float toolbarAlpha;
private int bottomOffset;
private View songListHeader;
private RecyclerView albumRecyclerView;
private Spanned biography;
private ArtistAlbumAdapter albumAdapter;
private ArtistSongAdapter songAdapter;
private ArrayList<Song> songs;
private ArrayList<Album> albums;
private final SmallObservableScrollViewCallbacks observableScrollViewCallbacks = new SmallObservableScrollViewCallbacks() {
@Override
@ -97,9 +109,9 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
ViewHelper.setTranslationY(songsBackgroundView, Math.max(0, -scrollY + artistImageViewHeight));
// Change alpha of overlay
float alpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange));
ViewUtil.setBackgroundAlpha(toolbar, alpha, toolbarColor);
ViewUtil.setBackgroundAlpha(statusBar, alpha, toolbarColor);
toolbarAlpha = Math.max(0, Math.min(1, (float) scrollY / flexibleRange));
ViewUtil.setBackgroundAlpha(toolbar, toolbarAlpha, toolbarColor);
setStatusBarColor(Util.getColorWithAlpha(cab != null && cab.isActive() ? 1 : toolbarAlpha, toolbarColor));
// Translate name text
int maxTitleTranslationY = artistImageViewHeight;
@ -107,27 +119,23 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
titleTranslationY = Math.max(headerOffset, titleTranslationY);
ViewHelper.setTranslationY(artistNameTv, titleTranslationY);
// Translate FAB
int fabTranslationY = titleTranslationY + titleViewHeight - (getFab().getHeight() / 2);
ViewHelper.setTranslationY(getFab(), fabTranslationY);
}
};
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(true);
setStatusBarTransparent();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_artist_detail);
App.bus.register(this);
if (Util.isAtLeastLollipop()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
postponeEnterTransition();
if (PreferenceUtils.getInstance(this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
}
getIntentExtras();
@ -139,42 +147,56 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
getSupportActionBar().setTitle(null);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (Util.isAtLeastLollipop()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fixLollipopTransitionImageWrongSize();
startPostponedEnterTransition();
}
}
@Override
protected boolean shouldColorStatusBar() {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getEnterTransition().addListener(new SmallTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
artistImageBackground.setVisibility(View.INVISIBLE);
}
@Override
protected boolean shouldColorNavBar() {
return false;
@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 void initViews() {
artistImage = (ImageView) findViewById(R.id.artist_image);
artistImageBackground = (ImageView) findViewById(R.id.artist_image_background);
toolbar = (Toolbar) findViewById(R.id.toolbar);
songListView = (ObservableListView) findViewById(R.id.list);
artistNameTv = (TextView) findViewById(R.id.artist_name);
songsBackgroundView = findViewById(R.id.list_background);
statusBar = findViewById(R.id.statusBar);
songListHeader = LayoutInflater.from(this).inflate(R.layout.artist_detail_header, songListView, false);
albumRecyclerView = (RecyclerView) songListHeader.findViewById(R.id.recycler_view);
}
private void setUpObservableListViewParams() {
bottomOffset = getResources().getDimensionPixelSize(R.dimen.bottom_offset_fab_activity);
artistImageViewHeight = getResources().getDimensionPixelSize(R.dimen.header_image_height);
toolbarColor = DialogUtils.resolveColor(this, R.attr.default_bar_color);
int toolbarHeight = Util.getActionBarSize(this);
titleViewHeight = getResources().getDimensionPixelSize(R.dimen.title_view_height);
headerOffset = toolbarHeight;
if (Util.isAtLeastKitKat())
headerOffset += getResources().getDimensionPixelSize(R.dimen.statusMargin);
headerOffset += getResources().getDimensionPixelSize(R.dimen.status_bar_padding);
}
@Override
@ -196,22 +218,22 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
loadBiography();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setNavigationBarColored(boolean colored) {
if (colored) {
if (Util.isAtLeastLollipop()) getWindow().setNavigationBarColor(toolbarColor);
setNavigationBarColor(toolbarColor);
} else {
if (Util.isAtLeastLollipop()) getWindow().setNavigationBarColor(Color.BLACK);
setNavigationBarColor(Color.BLACK);
}
}
private void setUpSongListView() {
songListView.setScrollViewCallbacks(observableScrollViewCallbacks);
songListView.setPadding(0, artistImageViewHeight + titleViewHeight, 0, 0);
songListView.setPadding(0, artistImageViewHeight + titleViewHeight, 0, bottomOffset);
songListView.addHeaderView(songListHeader);
final ArrayList<Song> songs = ArtistSongLoader.getArtistSongList(this, artist.id);
ArtistSongAdapter songAdapter = new ArtistSongAdapter(this, songs);
songs = ArtistSongLoader.getArtistSongList(this, artist.id);
songAdapter = new ArtistSongAdapter(this, songs, this);
songListView.setAdapter(songAdapter);
final View contentView = getWindow().getDecorView().findViewById(android.R.id.content);
@ -222,23 +244,12 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
observableScrollViewCallbacks.onScrollChanged(-(artistImageViewHeight + titleViewHeight), false, false);
}
});
songListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// header view has position 0
if (position == 0) {
return;
}
MusicPlayerRemote.openQueue(songs, position - 1, true);
}
});
}
private void setUpAlbumRecyclerView() {
albumRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
List<Album> albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id);
albumAdapter = new ArtistAlbumAdapter(this, albums);
albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id);
albumAdapter = new ArtistAlbumAdapter(this, albums, this);
albumRecyclerView.setAdapter(albumAdapter);
}
@ -264,6 +275,8 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
}
private void setUpArtistImageAndApplyPalette(final boolean forceDownload) {
final StackBlurManager defaultArtistImageBlurManager = new StackBlurManager(BitmapFactory.decodeResource(getResources(), R.drawable.default_artist_image));
artistImageBackground.setImageBitmap(defaultArtistImageBlurManager.process(10));
LastFMArtistImageUrlLoader.loadArtistImageUrl(this, artist.name, forceDownload, new LastFMArtistImageUrlLoader.ArtistImageUrlLoaderCallback() {
@Override
public void onArtistImageUrlLoaded(final String url) {
@ -279,11 +292,13 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
applyPalette(null);
artistImageBackground.setImageBitmap(defaultArtistImageBlurManager.returnBlurredImage());
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
applyPalette(loadedImage);
artistImageBackground.setImageBitmap(new StackBlurManager(loadedImage).process(10));
}
}
);
@ -295,16 +310,16 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
if (bitmap != null) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
toolbarColor = vibrantSwatch.getRgb();
artistNameTv.setBackgroundColor(vibrantSwatch.getRgb());
artistNameTv.setTextColor(vibrantSwatch.getTitleTextColor());
artistNameTv.setTextColor(Util.getOpaqueColor(vibrantSwatch.getTitleTextColor()));
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(ArtistDetailActivity.this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(vibrantSwatch.getRgb());
setNavigationBarColor(vibrantSwatch.getRgb());
notifyTaskColorChange(toolbarColor);
} else {
resetColors();
@ -333,7 +348,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
return toolbarColor;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void resetColors() {
int titleTextColor = DialogUtils.resolveColor(this, R.attr.title_text_color);
int defaultBarColor = DialogUtils.resolveColor(this, R.attr.default_bar_color);
@ -343,7 +358,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
artistNameTv.setTextColor(titleTextColor);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(this).coloredNavigationBarArtistEnabled())
getWindow().setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
notifyTaskColorChange(toolbarColor);
}
@ -411,7 +426,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
toolbar.setEnabled(false);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void fixLollipopTransitionImageWrongSize() {
getWindow().getSharedElementEnterTransition().addListener(new Transition.TransitionListener() {
@Override
@ -441,6 +456,22 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
});
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.SONGS_CHANGED:
case DataBaseChangedEvent.ALBUMS_CHANGED:
case DataBaseChangedEvent.ARTISTS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
songs = ArtistSongLoader.getArtistSongList(this, artist.id);
songAdapter.updateDataSet(songs);
albums = ArtistAlbumLoader.getArtistAlbumList(this, artist.id);
albumAdapter.updateDataSet(albums);
if (songs.size() < 1) finish();
break;
}
}
@Subscribe
public void onUIPreferenceChanged(UIPreferenceChangedEvent event) {
switch (event.getAction()) {
@ -455,4 +486,37 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
super.onDestroy();
App.bus.unregister(this);
}
@Override
public MaterialCab openCab(int menuRes, final MaterialCab.Callback callback) {
if (cab != null && cab.isActive()) cab.finish();
cab = new MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setBackgroundColor(getPaletteColor())
.start(new MaterialCab.Callback() {
@Override
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
setStatusBarColor(Util.getOpaqueColor(toolbarColor));
return callback.onCabCreated(materialCab, menu);
}
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
return callback.onCabItemClicked(menuItem);
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
setStatusBarColor(Util.getColorWithAlpha(toolbarAlpha, toolbarColor));
return callback.onCabFinished(materialCab);
}
});
return cab;
}
@Override
public void onBackPressed() {
if (cab != null && cab.isActive()) cab.finish();
else super.onBackPressed();
}
}

View file

@ -1,12 +1,16 @@
package com.kabouzeid.gramophone.ui.activities;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.util.Pair;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
@ -16,22 +20,23 @@ import android.support.v7.internal.view.menu.MenuPopupHelper;
import android.support.v7.widget.ActionMenuPresenter;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.widget.FrameLayout;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialcab.MaterialCab;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.astuetz.PagerSlidingTabStrip;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.PagerAdapter;
import com.kabouzeid.gramophone.dialogs.AboutDialog;
import com.kabouzeid.gramophone.dialogs.CreatePlaylistDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.loader.ArtistSongLoader;
@ -40,7 +45,6 @@ import com.kabouzeid.gramophone.model.MusicRemoteEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.ui.fragments.NavigationDrawerFragment;
import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AbsMainActivityFragment;
import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AlbumViewFragment;
import com.kabouzeid.gramophone.util.MusicUtil;
@ -57,46 +61,37 @@ import java.util.List;
import java.util.Set;
public class MainActivity extends AbsFabActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks, KabViewsDisableAble {
implements KabViewsDisableAble, CabHolder, View.OnClickListener {
public static final String TAG = MainActivity.class.getSimpleName();
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private NavigationDrawerFragment navigationDrawerFragment;
private Toolbar toolbar;
private PagerAdapter pagerAdapter;
private ViewPager viewPager;
private PagerSlidingTabStrip slidingTabLayout;
private TabLayout tabLayout;
private int currentPage = -1;
private MaterialCab cab;
private NavigationView navigationView;
private View navigationDrawerHeader;
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(!Util.isAtLeastLollipop());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
navigationDrawerFragment.setUp(
drawerLayout
);
setUpDrawerLayout();
setUpToolBar();
setUpViewPager();
if (PreferenceUtils.getInstance(this).coloredNavigationBarOtherScreensEnabled())
setNavigationBarThemeColor();
handlePlaybackIntent(getIntent());
}
@Override
protected boolean shouldColorStatusBar() {
return !Util.isAtLeastLollipop();
}
@Override
protected boolean shouldColorNavBar() {
return PreferenceUtils.getInstance(this).coloredNavigationBarOtherScreensEnabled();
}
private void setUpViewPager() {
pagerAdapter = new PagerAdapter(this, getSupportFragmentManager());
final PagerAdapter.MusicFragments[] fragments = PagerAdapter.MusicFragments.values();
@ -110,52 +105,119 @@ public class MainActivity extends AbsFabActivity
int startPosition = PreferenceUtils.getInstance(this).getDefaultStartPage();
startPosition = startPosition == -1 ? PreferenceUtils.getInstance(this).getLastStartPage() : startPosition;
currentPage = startPosition;
viewPager.setCurrentItem(startPosition);
navigationDrawerFragment.setItemChecked(startPosition);
navigationView.getMenu().getItem(startPosition).setChecked(true);
slidingTabLayout.setIndicatorColor(ThemeSingleton.get().positiveColor);
slidingTabLayout.setViewPager(viewPager);
slidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
tabLayout.setupWithViewPager(viewPager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(final int position) {
navigationDrawerFragment.setItemChecked(position);
public void onPageSelected(int position) {
navigationView.getMenu().getItem(position).setChecked(true);
currentPage = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
viewPager.setCurrentItem(startPosition);
}
private void initViews() {
viewPager = (ViewPager) findViewById(R.id.pager);
slidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabLayout = (TabLayout) findViewById(R.id.tabs);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
navigationView = (NavigationView) findViewById(R.id.nav_view);
}
private void setUpToolBar() {
setTitle(getResources().getString(R.string.app_name));
toolbar = (Toolbar) findViewById(R.id.toolbar);
setToolBarTransparent(PreferenceUtils.getInstance(this).transparentToolbar());
setToolBarColor();
setSupportActionBar(toolbar);
setUpDrawerToggle();
}
private void setToolBarTransparent(boolean transparent) {
float alpha = transparent ? 0.9f : 1f;
final int colorPrimary = PreferenceUtils.getInstance(this).getThemeColorPrimary();
ViewUtil.setBackgroundAlpha(toolbar, alpha, colorPrimary);
ViewUtil.setBackgroundAlpha(slidingTabLayout, alpha, colorPrimary);
private void setToolBarColor() {
final int colorPrimary = getThemeColorPrimary();
toolbar.setBackgroundColor(colorPrimary);
tabLayout.setBackgroundColor(colorPrimary);
}
private void setUpNavigationView() {
final int colorAccent = ThemeSingleton.get().positiveColor;
navigationView.setItemTextColor(new ColorStateList(
new int[][]{
//{-android.R.attr.state_enabled}, // disabled
{android.R.attr.state_checked}, // checked
{} // default
},
new int[]{
// 0,
colorAccent,
ThemeSingleton.get().darkTheme ? Color.argb(222, 255, 255, 255) : Color.argb(222, 0, 0, 0)
}
));
navigationView.setItemIconTintList(new ColorStateList(
new int[][]{
//{-android.R.attr.state_enabled}, // disabled
{android.R.attr.state_checked}, // checked
{} // default
},
new int[]{
// 0,
colorAccent,
ThemeSingleton.get().darkTheme ? Color.argb(138, 255, 255, 255) : Color.argb(138, 0, 0, 0)
}
));
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
drawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
case R.id.nav_songs:
menuItem.setChecked(true);
viewPager.setCurrentItem(PagerAdapter.MusicFragments.SONG.ordinal(), true);
break;
case R.id.nav_albums:
menuItem.setChecked(true);
viewPager.setCurrentItem(PagerAdapter.MusicFragments.ALBUM.ordinal(), true);
break;
case R.id.nav_artists:
menuItem.setChecked(true);
viewPager.setCurrentItem(PagerAdapter.MusicFragments.ARTIST.ordinal(), true);
break;
case R.id.nav_playlists:
menuItem.setChecked(true);
viewPager.setCurrentItem(PagerAdapter.MusicFragments.PLAYLIST.ordinal(), true);
break;
case R.id.nav_settings:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
}
}, 200);
break;
case R.id.nav_about:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
new AboutDialog().show(getSupportFragmentManager(), "ABOUT_DIALOG");
}
}, 200);
break;
}
return true;
}
});
}
private void setUpDrawerToggle() {
@ -175,19 +237,8 @@ public class MainActivity extends AbsFabActivity
}
private void setUpDrawerLayout() {
drawerLayout.setStatusBarBackgroundColor(PreferenceUtils
.getInstance(this).getThemeColorPrimaryDarker());
FrameLayout navDrawerFrame = (FrameLayout) findViewById(R.id.nav_drawer_frame);
int navDrawerMargin = getResources().getDimensionPixelSize(R.dimen.nav_drawer_margin);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int navDrawerWidthLimit = getResources().getDimensionPixelSize(R.dimen.nav_drawer_width_limit);
int navDrawerWidth = displayMetrics.widthPixels - navDrawerMargin;
if (navDrawerWidth > navDrawerWidthLimit) {
navDrawerWidth = navDrawerWidthLimit;
}
navDrawerFrame.setLayoutParams(new DrawerLayout.LayoutParams(navDrawerWidth,
DrawerLayout.LayoutParams.MATCH_PARENT, Gravity.START));
drawerLayout.setStatusBarBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimaryDarker());
setUpNavigationView();
}
@Override
@ -202,21 +253,26 @@ public class MainActivity extends AbsFabActivity
}
private void updateNavigationDrawerHeader() {
if (navigationDrawerFragment != null) {
Song song = MusicPlayerRemote.getCurrentSong();
if (song.id != -1) {
navigationDrawerFragment.getSongTitle().setText(song.title);
navigationDrawerFragment.getSongArtist().setText(song.artistName);
ImageLoader.getInstance().displayImage(
MusicUtil.getAlbumArtUri(song.albumId).toString(),
navigationDrawerFragment.getAlbumArtImageView(),
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.build()
);
Song song = MusicPlayerRemote.getCurrentSong();
if (song.id != -1) {
if (navigationDrawerHeader == null) {
navigationDrawerHeader = navigationView.inflateHeaderView(R.layout.navigation_drawer_header);
navigationDrawerHeader.setOnClickListener(this);
}
((TextView) navigationDrawerHeader.findViewById(R.id.song_title)).setText(song.title);
((TextView) navigationDrawerHeader.findViewById(R.id.song_artist)).setText(song.artistName);
ImageLoader.getInstance().displayImage(
MusicUtil.getAlbumArtUri(song.albumId).toString(),
((ImageView) navigationDrawerHeader.findViewById(R.id.album_art)),
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.build()
);
} else {
navigationView.removeHeaderView(navigationDrawerHeader);
navigationDrawerHeader = null;
}
}
@ -249,37 +305,6 @@ public class MainActivity extends AbsFabActivity
}
}
@Override
public void onNavigationDrawerItemSelected(int position) {
if (position == NavigationDrawerFragment.NAVIGATION_DRAWER_HEADER) {
NavigationUtil.openCurrentPlayingIfPossible(this, getSharedViewsWithFab(new Pair[]{
Pair.create(navigationDrawerFragment.getAlbumArtImageView(),
getResources().getString(R.string.transition_album_cover)
)
}));
} else if (position == NavigationDrawerFragment.ABOUT_INDEX) {
drawerLayout.closeDrawers();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
new AboutDialog().show(getSupportFragmentManager(), "ABOUT_DIALOG");
}
}, 200);
} else if (position == NavigationDrawerFragment.SETTINGS_INDEX) {
drawerLayout.closeDrawers();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
}
}, 200);
} else {
if (viewPager != null) {
viewPager.setCurrentItem(position, true);
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (isAlbumPage()) {
@ -343,17 +368,17 @@ public class MainActivity extends AbsFabActivity
public void onUIPreferenceChangedEvent(UIPreferenceChangedEvent event) {
super.onUIPreferenceChangedEvent(event);
switch (event.getAction()) {
case UIPreferenceChangedEvent.TOOLBAR_TRANSPARENT_CHANGED:
setToolBarTransparent((boolean) event.getValue());
break;
case UIPreferenceChangedEvent.COLORED_NAVIGATION_BAR_OTHER_SCREENS_CHANGED:
setShouldColorNavBar((boolean) event.getValue());
if ((boolean) event.getValue()) setNavigationBarThemeColor();
else resetNavigationBarColor();
break;
case UIPreferenceChangedEvent.COLORED_NAVIGATION_BAR_CHANGED:
try {
setShouldColorNavBar(((Set) event.getValue()).contains(PreferenceUtils.COLORED_NAVIGATION_BAR_OTHER_SCREENS));
if (((Set) event.getValue()).contains(PreferenceUtils.COLORED_NAVIGATION_BAR_OTHER_SCREENS))
setNavigationBarThemeColor();
else resetNavigationBarColor();
} catch (NullPointerException ignored) {
setShouldColorNavBar(false);
resetNavigationBarColor();
}
break;
}
@ -361,11 +386,9 @@ public class MainActivity extends AbsFabActivity
@Override
public void onBackPressed() {
if (navigationDrawerFragment.isDrawerOpen()) {
drawerLayout.closeDrawers();
return;
}
super.onBackPressed();
if (drawerLayout.isDrawerOpen(navigationView)) drawerLayout.closeDrawers();
else if (cab != null && cab.isActive()) cab.finish();
else super.onBackPressed();
}
@Override
@ -553,4 +576,25 @@ public class MainActivity extends AbsFabActivity
});
return super.onMenuOpened(featureId, menu);
}
@Override
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
if (cab != null && cab.isActive()) cab.finish();
cab = new MaterialCab(this, R.id.cab_stub)
.setMenu(menu)
.setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary())
.start(callback);
return cab;
}
@Override
public void onClick(View v) {
if (v == navigationDrawerHeader) {
NavigationUtil.openCurrentPlayingIfPossible(this, getSharedViewsWithFab(new Pair[]{
Pair.create(((ImageView) navigationDrawerHeader.findViewById(R.id.album_art)),
getResources().getString(R.string.transition_album_cover)
)
}));
}
}
}

View file

@ -1,17 +1,21 @@
package com.kabouzeid.gramophone.ui.activities;
import android.annotation.TargetApi;
import android.animation.Animator;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.graphics.Palette;
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.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
@ -21,17 +25,16 @@ import android.widget.TextView;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.SongDetailDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.lastfm.artist.LastFMArtistImageUrlLoader;
import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager;
import com.kabouzeid.gramophone.loader.SongFilePathLoader;
import com.kabouzeid.gramophone.misc.AppKeys;
import com.kabouzeid.gramophone.misc.SmallTransitionListener;
import com.kabouzeid.gramophone.model.MusicRemoteEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.ui.activities.tageditor.SongTagEditorActivity;
@ -40,24 +43,22 @@ import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.kabouzeid.gramophone.views.SquareIfPlaceImageView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.squareup.otto.Subscribe;
import java.io.File;
public class MusicControllerActivity extends AbsFabActivity {
public static final String TAG = MusicControllerActivity.class.getSimpleName();
private static final int DEFAULT_DELAY = 350;
private static final int DEFAULT_ANIMATION_TIME = 1000;
private static final int COLOR_TRANSITION_TIME = 400;
private Song song;
private ImageView albumArt;
private ImageView artistImage;
private SquareIfPlaceImageView albumArt;
private ImageView albumArtBackground;
private TextView songTitle;
private TextView songArtist;
private TextView currentSongProgress;
@ -69,30 +70,58 @@ public class MusicControllerActivity extends AbsFabActivity {
private ImageButton repeatButton;
private ImageButton shuffleButton;
private View mediaControllerContainer;
private Toolbar toolbar;
private int lastFooterColor = -1;
private int lastTextColor = -2;
private boolean killThreads = false;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private boolean opaqueToolBar = PreferenceUtils.getInstance(this).opaqueToolbarNowPlaying();
private boolean forceSquareAlbumArt = PreferenceUtils.getInstance(this).forceAlbumArtSquared();
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(true);
setStatusBarTransparent();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_controller);
App.bus.register(this);
initViews();
albumArtBackground.setAlpha(0.7f);
moveSeekBarIntoPlace();
setUpMusicControllers();
prepareViewsForOpenAnimation();
albumArt.forceSquare(forceSquareAlbumArt);
setToolbarOpaque(opaqueToolBar);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(null);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getEnterTransition().addListener(new SmallTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
mediaControllerContainer.setVisibility(View.INVISIBLE);
}
@Override
public void onTransitionEnd(Transition transition) {
int cx = (getFab().getLeft() + getFab().getRight()) / 2;
int cy = (getFab().getTop() + getFab().getBottom()) / 2;
int finalRadius = Math.max(mediaControllerContainer.getWidth(), mediaControllerContainer.getHeight());
Animator animator = ViewAnimationUtils.createCircularReveal(mediaControllerContainer, cx, cy, getFab().getWidth() / 2, finalRadius);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(1000);
animator.start();
mediaControllerContainer.setVisibility(View.VISIBLE);
}
});
}
}
@Override
@ -101,22 +130,13 @@ public class MusicControllerActivity extends AbsFabActivity {
getFab().setOnLongClickListener(null);
}
@Override
protected boolean shouldColorStatusBar() {
return false; // let other code handle this below
}
@Override
protected boolean shouldColorNavBar() {
return false; // let other code handle this below
}
private void moveSeekBarIntoPlace() {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) progressSlider.getLayoutParams();
progressSlider.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
final int seekBarMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.seek_bar_margin_left_right);
lp.setMargins(seekBarMarginLeftRight, 0, seekBarMarginLeftRight, -(progressSlider.getMeasuredHeight() / 2));
progressSlider.setLayoutParams(lp);
// RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) progressSlider.getLayoutParams();
// progressSlider.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
// final int seekBarMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.seek_bar_margin_left_right);
// lp.setMargins(seekBarMarginLeftRight, 0, seekBarMarginLeftRight, -(progressSlider.getMeasuredHeight() / 2));
// progressSlider.setLayoutParams(lp);
}
private void initViews() {
@ -124,8 +144,8 @@ public class MusicControllerActivity extends AbsFabActivity {
prevButton = (ImageButton) findViewById(R.id.prev_button);
repeatButton = (ImageButton) findViewById(R.id.repeat_button);
shuffleButton = (ImageButton) findViewById(R.id.shuffle_button);
albumArt = (ImageView) findViewById(R.id.album_art);
artistImage = (ImageView) findViewById(R.id.artist_image);
albumArt = (SquareIfPlaceImageView) findViewById(R.id.album_art);
albumArtBackground = (ImageView) findViewById(R.id.album_art_background);
songTitle = (TextView) findViewById(R.id.song_title);
songArtist = (TextView) findViewById(R.id.song_artist);
currentSongProgress = (TextView) findViewById(R.id.song_current_progress);
@ -133,6 +153,7 @@ public class MusicControllerActivity extends AbsFabActivity {
footer = findViewById(R.id.footer);
progressSlider = (SeekBar) findViewById(R.id.progress_slider);
mediaControllerContainer = findViewById(R.id.media_controller_container);
toolbar = (Toolbar) findViewById(R.id.toolbar);
}
private void setUpMusicControllers() {
@ -140,43 +161,13 @@ public class MusicControllerActivity extends AbsFabActivity {
setUpRepeatButton();
setUpShuffleButton();
setUpProgressSlider();
setUpBox(PreferenceUtils.getInstance(this).playbackControllerBoxEnabled());
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setUpBox(boolean boxEnabled) {
if (boxEnabled) {
if (Util.isAtLeastLollipop()) {
mediaControllerContainer.setElevation(getResources().getDimensionPixelSize(R.dimen.cardview_default_elevation));
}
mediaControllerContainer.setBackgroundColor(
DialogUtils.resolveColor(this, R.attr.music_controller_container_color));
} else {
if (Util.isAtLeastLollipop() && !Util.isInPortraitMode(this)) {
mediaControllerContainer.setElevation(getResources().getDimensionPixelSize(R.dimen.cardview_default_elevation));
mediaControllerContainer.setBackgroundColor(
DialogUtils.resolveColor(this, R.attr.music_controller_container_color));
} else {
mediaControllerContainer.setBackground(null);
}
}
}
private static void setTint(SeekBar seekBar, int color) {
ColorStateList s1 = ColorStateList.valueOf(color);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
seekBar.setThumbTintList(s1);
seekBar.setProgressTintList(s1);
} else {
seekBar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
seekBar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
seekBar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
private void setUpProgressSlider() {
setTint(progressSlider, ThemeSingleton.get().positiveColor);
progressSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@ -228,7 +219,7 @@ public class MusicControllerActivity extends AbsFabActivity {
switch (MusicPlayerRemote.getShuffleMode()) {
case MusicService.SHUFFLE_MODE_SHUFFLE:
shuffleButton.setImageDrawable(Util.getTintedDrawable(this, R.drawable.ic_shuffle_white_48dp,
ThemeSingleton.get().positiveColor));
getThemeColorAccent() == Color.WHITE ? Color.BLACK : getThemeColorAccent()));
break;
default:
shuffleButton.setImageDrawable(Util.getTintedDrawable(this, R.drawable.ic_shuffle_white_48dp,
@ -255,19 +246,15 @@ public class MusicControllerActivity extends AbsFabActivity {
break;
case MusicService.REPEAT_MODE_ALL:
repeatButton.setImageDrawable(Util.getTintedDrawable(this, R.drawable.ic_repeat_white_48dp,
ThemeSingleton.get().positiveColor));
getThemeColorAccent() == Color.WHITE ? Color.BLACK : getThemeColorAccent()));
break;
default:
repeatButton.setImageDrawable(Util.getTintedDrawable(this, R.drawable.ic_repeat_one_white_48dp,
ThemeSingleton.get().positiveColor));
getThemeColorAccent() == Color.WHITE ? Color.BLACK : getThemeColorAccent()));
break;
}
}
private void prepareViewsForOpenAnimation() {
footer.setPivotY(0);
footer.setScaleY(0);
}
@Override
public String getTag() {
@ -277,6 +264,7 @@ public class MusicControllerActivity extends AbsFabActivity {
@Override
protected void onResume() {
super.onResume();
updateControllerState();
startMusicControllerStateUpdateThread();
updateCurrentSong();
}
@ -284,7 +272,6 @@ public class MusicControllerActivity extends AbsFabActivity {
private void updateCurrentSong() {
getCurrentSong();
setHeadersText();
setUpArtistArt();
setUpAlbumArtAndApplyPalette();
totalSongDuration.setText(MusicUtil.getReadableDurationString(song.duration));
currentSongProgress.setText(MusicUtil.getReadableDurationString(-1));
@ -307,17 +294,18 @@ public class MusicControllerActivity extends AbsFabActivity {
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.build(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
applyPalette(null);
albumArtBackground.setImageBitmap(new StackBlurManager(BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art)).process(10));
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
applyPalette(loadedImage);
albumArtBackground.setImageBitmap(new StackBlurManager(loadedImage).process(10));
}
}
);
@ -333,8 +321,7 @@ public class MusicControllerActivity extends AbsFabActivity {
if (vibrantSwatch != null) {
final int swatchRgb = vibrantSwatch.getRgb();
animateColorChange(swatchRgb);
songTitle.setTextColor(vibrantSwatch.getTitleTextColor());
songArtist.setTextColor(vibrantSwatch.getBodyTextColor());
animateTextColorChange(Util.getOpaqueColor(vibrantSwatch.getTitleTextColor()));
notifyTaskColorChange(swatchRgb);
} else {
resetColors();
@ -347,48 +334,51 @@ public class MusicControllerActivity extends AbsFabActivity {
}
private void resetColors() {
final int songTitleTextColor = DialogUtils.resolveColor(this, R.attr.title_text_color);
final int artistNameTextColor = DialogUtils.resolveColor(this, R.attr.caption_text_color);
final int textColor = Util.getOpaqueColor(DialogUtils.resolveColor(this, R.attr.title_text_color));
final int defaultBarColor = DialogUtils.resolveColor(this, R.attr.default_bar_color);
animateColorChange(defaultBarColor);
animateTextColorChange(textColor);
songTitle.setTextColor(songTitleTextColor);
songArtist.setTextColor(artistNameTextColor);
currentSongProgress.setTextColor(DialogUtils.resolveColor(MusicControllerActivity.this, R.attr.themed_drawable_color));
totalSongDuration.setTextColor(DialogUtils.resolveColor(MusicControllerActivity.this, R.attr.themed_drawable_color));
notifyTaskColorChange(defaultBarColor);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void animateColorChange(final int newColor) {
if (lastFooterColor != -1 && lastFooterColor != newColor) {
ViewUtil.animateViewColor(footer, lastFooterColor, newColor, 300);
ViewUtil.animateViewColor(footer, lastFooterColor, newColor, COLOR_TRANSITION_TIME);
if (opaqueToolBar)
ViewUtil.animateViewColor(toolbar, lastFooterColor, newColor, COLOR_TRANSITION_TIME);
else toolbar.setBackgroundColor(Color.TRANSPARENT);
} else {
footer.setBackgroundColor(newColor);
if (opaqueToolBar) toolbar.setBackgroundColor(newColor);
else toolbar.setBackgroundColor(Color.TRANSPARENT);
}
setTint(progressSlider, !ThemeSingleton.get().darkTheme && getThemeColorAccent() == Color.WHITE ? Color.BLACK : getThemeColorAccent());
if (opaqueToolBar) setStatusBarColor(newColor);
else setStatusBarColor(Color.TRANSPARENT);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(this).coloredNavigationBarCurrentPlayingEnabled())
getWindow().setNavigationBarColor(newColor);
setNavigationBarColor(newColor);
lastFooterColor = newColor;
}
private void setUpArtistArt() {
if (artistImage != null) {
artistImage.setImageResource(R.drawable.default_artist_image);
LastFMArtistImageUrlLoader.loadArtistImageUrl(this, song.artistName, false, new LastFMArtistImageUrlLoader.ArtistImageUrlLoaderCallback() {
@Override
public void onArtistImageUrlLoaded(String url) {
ImageLoader.getInstance().displayImage(url,
artistImage,
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.showImageOnFail(R.drawable.default_artist_image)
.resetViewBeforeLoading(true)
.build()
);
}
});
private void animateTextColorChange(final int newColor) {
if (lastTextColor != -2 && lastTextColor != newColor) {
ViewUtil.animateTextColor(songTitle, lastTextColor, newColor, COLOR_TRANSITION_TIME);
ViewUtil.animateTextColor(songArtist, lastTextColor, newColor, COLOR_TRANSITION_TIME);
} else {
songTitle.setTextColor(newColor);
songArtist.setTextColor(newColor);
}
lastTextColor = newColor;
}
private void getCurrentSong() {
@ -430,9 +420,8 @@ public class MusicControllerActivity extends AbsFabActivity {
}).start();
}
@Override
protected void updateControllerState() {
super.updateControllerState();
updateFabState();
updateRepeatState();
updateShuffleState();
}
@ -459,14 +448,6 @@ public class MusicControllerActivity extends AbsFabActivity {
killThreads = true;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
animateActivityOpened(DEFAULT_DELAY);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_music_playing, menu);
@ -513,28 +494,16 @@ public class MusicControllerActivity extends AbsFabActivity {
return super.onOptionsItemSelected(item);
}
private void animateActivityOpened(int startDelay) {
ViewPropertyAnimator.animate(footer)
.scaleX(1)
.scaleY(1)
.setInterpolator(new DecelerateInterpolator(4))
.setDuration(DEFAULT_ANIMATION_TIME)
.setStartDelay(startDelay)
.start();
}
@Subscribe
public void onUIPrefsChanged(UIPreferenceChangedEvent event) {
switch (event.getAction()) {
case UIPreferenceChangedEvent.PLAYBACK_CONTROLLER_CARD_CHANGED:
setUpBox((boolean) event.getValue());
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
App.bus.unregister(this);
private void setToolbarOpaque(boolean toolbarOpaque) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) findViewById(R.id.album_art_frame).getLayoutParams();
if (!toolbarOpaque) {
if (Build.VERSION.SDK_INT > 16) {
params.removeRule(RelativeLayout.BELOW);
} else {
params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.ABOVE, R.id.footer_frame);
}
} else params.addRule(RelativeLayout.BELOW, R.id.toolbar_frame);
}
}

View file

@ -1,7 +1,5 @@
package com.kabouzeid.gramophone.ui.activities;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
@ -10,39 +8,45 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.afollestad.materialcab.MaterialCab;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.songadapter.PlaylistSongAdapter;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.PlaylistLoader;
import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
import com.kabouzeid.gramophone.misc.AppKeys;
import com.kabouzeid.gramophone.misc.DragSortRecycler;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
public class PlaylistDetailActivity extends AbsFabActivity {
public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder {
public static final String TAG = PlaylistDetailActivity.class.getSimpleName();
private Playlist playlist;
private MaterialCab cab;
private PlaylistSongAdapter adapter;
private ArrayList<PlaylistSong> songs;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(!Util.isAtLeastLollipop());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playlist_detail);
getIntentExtras();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
final ArrayList<PlaylistSong> songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
final PlaylistSongAdapter adapter = new PlaylistSongAdapter(this, songs);
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
adapter = new PlaylistSongAdapter(this, songs, this);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
recyclerView.setAdapter(adapter);
@ -72,16 +76,12 @@ public class PlaylistDetailActivity extends AbsFabActivity {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(playlist.name);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected boolean shouldColorStatusBar() {
return true;
}
if (PreferenceUtils.getInstance(this).coloredNavigationBarPlaylistEnabled())
setNavigationBarThemeColor();
setStatusBarThemeColor();
@Override
protected boolean shouldColorNavBar() {
return PreferenceUtils.getInstance(this).coloredNavigationBarPlaylistEnabled();
App.bus.register(this);
}
private void getIntentExtras() {
@ -123,4 +123,40 @@ public class PlaylistDetailActivity extends AbsFabActivity {
}
return super.onOptionsItemSelected(item);
}
@Override
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
if (cab != null && cab.isActive()) cab.finish();
cab = new MaterialCab(this, R.id.cab_stub)
.setMenu(menu)
.setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary())
.start(callback);
return cab;
}
@Override
protected void onDestroy() {
super.onDestroy();
App.bus.unregister(this);
}
@Subscribe
public void onDataBaseEvent(DataBaseChangedEvent event) {
switch (event.getAction()) {
case DataBaseChangedEvent.PLAYLISTS_CHANGED:
case DataBaseChangedEvent.DATABASE_CHANGED:
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
adapter.updateDataSet(songs);
findViewById(android.R.id.empty).setVisibility(
songs.size() == 0 ? View.VISIBLE : View.GONE
);
break;
}
}
@Override
public void onBackPressed() {
if (cab != null && cab.isActive()) cab.finish();
else super.onBackPressed();
}
}

View file

@ -34,7 +34,6 @@ public class SearchActivity extends AbsBaseActivity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(false);
setTitle(null);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
@ -60,16 +59,9 @@ public class SearchActivity extends AbsBaseActivity {
setSupportActionBar(toolbar);
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected boolean shouldColorStatusBar() {
return true;
}
@Override
protected boolean shouldColorNavBar() {
return true;
setNavigationBarThemeColor();
setStatusBarThemeColor();
}
@Override

View file

@ -22,7 +22,6 @@ import com.kabouzeid.gramophone.prefs.ColorChooserPreference;
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import java.util.Set;
@ -31,7 +30,6 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(!Util.isAtLeastLollipop());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
@ -42,16 +40,10 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
if (savedInstanceState == null)
getFragmentManager().beginTransaction().replace(R.id.content_frame, new SettingsFragment()).commit();
}
@Override
protected boolean shouldColorStatusBar() {
return true;
}
@Override
protected boolean shouldColorNavBar() {
return PreferenceUtils.getInstance(this).coloredNavigationBarOtherScreensEnabled();
if (PreferenceUtils.getInstance(this).coloredNavigationBarOtherScreensEnabled())
setNavigationBarThemeColor();
setStatusBarThemeColor();
}
@Override
@ -121,14 +113,6 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
}
});
findPreference("transparent_toolbar").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
App.bus.post(new UIPreferenceChangedEvent(UIPreferenceChangedEvent.TOOLBAR_TRANSPARENT_CHANGED, o));
return true;
}
});
findPreference("colored_album_footers").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
@ -137,14 +121,6 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
}
});
findPreference("playback_controller_card").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
App.bus.post(new UIPreferenceChangedEvent(UIPreferenceChangedEvent.PLAYBACK_CONTROLLER_CARD_CHANGED, o));
return true;
}
});
Preference colorNavBar = findPreference("colored_navigation_bar");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
colorNavBar.setEnabled(false);
@ -207,13 +183,16 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
super.onUIPreferenceChangedEvent(event);
switch (event.getAction()) {
case UIPreferenceChangedEvent.COLORED_NAVIGATION_BAR_OTHER_SCREENS_CHANGED:
setShouldColorNavBar((boolean) event.getValue());
if ((boolean) event.getValue()) setNavigationBarThemeColor();
else resetNavigationBarColor();
break;
case UIPreferenceChangedEvent.COLORED_NAVIGATION_BAR_CHANGED:
try {
setShouldColorNavBar(((Set) event.getValue()).contains(PreferenceUtils.COLORED_NAVIGATION_BAR_OTHER_SCREENS));
if (((Set) event.getValue()).contains(PreferenceUtils.COLORED_NAVIGATION_BAR_OTHER_SCREENS))
setNavigationBarThemeColor();
else resetNavigationBarColor();
} catch (NullPointerException ignored) {
setShouldColorNavBar(false);
resetNavigationBarColor();
}
break;
}

View file

@ -1,7 +1,5 @@
package com.kabouzeid.gramophone.ui.activities.base;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import com.crashlytics.android.Crashlytics;
@ -65,7 +63,7 @@ public abstract class AbsBaseActivity extends ThemeBaseActivity implements KabVi
return areViewsEnabled;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void onUIPreferenceChangedEvent(UIPreferenceChangedEvent event) {
switch (event.getAction()) {
case UIPreferenceChangedEvent.THEME_CHANGED:

View file

@ -3,6 +3,7 @@ package com.kabouzeid.gramophone.ui.activities.base;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.util.Pair;
import android.util.Log;
import android.view.GestureDetector;
@ -13,14 +14,13 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.ColorChooserDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.misc.SmallOnGestureListener;
import com.kabouzeid.gramophone.model.MusicRemoteEvent;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.views.PlayPauseDrawable;
import com.melnykov.fab.FloatingActionButton;
import com.squareup.otto.Subscribe;
/**
@ -55,15 +55,10 @@ public abstract class AbsFabActivity extends AbsBaseActivity {
getFab().setImageDrawable(playPauseDrawable);
final int accentColor = ThemeSingleton.get().positiveColor;
getFab().setBackgroundTintList(Util.getEmptyColorStateList(accentColor));
if (accentColor == Color.WHITE) {
getFab().setColorNormal(accentColor);
getFab().setColorPressed(ColorChooserDialog.shiftColorDown(accentColor));
getFab().setColorRipple(ColorChooserDialog.shiftColorUp(accentColor));
getFab().getDrawable().setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
} else {
getFab().setColorNormal(accentColor);
getFab().setColorPressed(ColorChooserDialog.shiftColorUp(accentColor));
getFab().setColorRipple(ColorChooserDialog.shiftColorDown(accentColor));
getFab().getDrawable().clearColorFilter();
}
@ -113,7 +108,7 @@ public abstract class AbsFabActivity extends AbsBaseActivity {
});
}
private void updateFabState() {
protected void updateFabState() {
if (MusicPlayerRemote.isPlaying()) {
playPauseDrawable.setPause();
} else {
@ -135,10 +130,6 @@ public abstract class AbsFabActivity extends AbsBaseActivity {
@Override
protected void onResume() {
super.onResume();
updateControllerState();
}
protected void updateControllerState() {
updateFabState();
}
@ -190,4 +181,8 @@ public abstract class AbsFabActivity extends AbsBaseActivity {
private void setFabPause() {
playPauseDrawable.animatedPause();
}
private void setFabColor() {
}
}

View file

@ -1,44 +1,26 @@
package com.kabouzeid.gramophone.ui.activities.base;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.readystatesoftware.systembartint.SystemBarTintManager;
/**
* @author Aidan Follestad (afollestad)
*/
/**
* READ!
* <p/>
* Instructions:
* <p/>
* KitKat or Lollipop solid statusBar with the right color (primaryDark):
* - shouldColorStatusBar return true OR return false and call setStatusBarColor() in the activity with a custom color
* - setStatusBarTranslucent(!Util.isAtLeastLollipop())
* <p/>
* KitKat or Lollipop translucent statusBar (not the color is too dark on Lollipop and KitKat only does fading but MUCH better performance the setStatusBarColor in onScrollCallback)
* - shouldColorStatusBar return false DO NOT return true and do not call setStatusBarColor() in this case at all here
* - setStatusBarTranslucent(true)
* - use a view below the statusBar to color it
* @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid)
*/
public abstract class ThemeBaseActivity extends AppCompatActivity implements KabViewsDisableAble {
// private boolean mLastDarkTheme;
// private int mLastPrimary;
// private int mLastAccent;
private int colorPrimary;
private int colorPrimaryDarker;
private int colorAccent;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -47,23 +29,16 @@ public abstract class ThemeBaseActivity extends AppCompatActivity implements Kab
setupTheme();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setupTheme() {
// Apply colors to system UI if necessary
setShouldColorNavBar(shouldColorNavBar());
setShouldColorStatusBar(shouldColorStatusBar());
colorPrimary = PreferenceUtils.getInstance(this).getThemeColorPrimary();
colorPrimaryDarker = Util.shiftColorDown(colorPrimary);
colorAccent = PreferenceUtils.getInstance(this).getThemeColorAccent();
// Persist current values so the Activity knows if they change
// mLastDarkTheme = PreferenceUtils.getInstance(this).getGeneralTheme() == 1;
// mLastPrimary = PreferenceUtils.getInstance(this).getThemeColorPrimary();
// mLastAccent = PreferenceUtils.getInstance(this).getThemeColorAccent();
// Accent colors in dialogs, and any dynamic views that pull from this singleton
ThemeSingleton.get().positiveColor = PreferenceUtils.getInstance(this).getThemeColorAccent();
ThemeSingleton.get().positiveColor = colorAccent;
ThemeSingleton.get().negativeColor = ThemeSingleton.get().positiveColor;
ThemeSingleton.get().neutralColor = ThemeSingleton.get().positiveColor;
ThemeSingleton.get().widgetColor = ThemeSingleton.get().positiveColor;
// Dark theme
ThemeSingleton.get().darkTheme = PreferenceUtils.getInstance(this).getGeneralTheme() == R.style.Theme_MaterialMusic;
if (!overridesTaskColor()) {
@ -71,10 +46,6 @@ public abstract class ThemeBaseActivity extends AppCompatActivity implements Kab
}
}
protected boolean overridesTaskColor() {
return false;
}
protected void notifyTaskColorChange(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Sets color of entry in the system recents page
@ -86,62 +57,58 @@ public abstract class ThemeBaseActivity extends AppCompatActivity implements Kab
}
}
// @Override
// protected void onResume() {
// super.onResume();
// if (mLastDarkTheme != (PreferenceUtils.getInstance(this).getGeneralTheme() == 1) ||
// mLastPrimary != PreferenceUtils.getInstance(this).getThemeColorPrimary() ||
// mLastAccent != PreferenceUtils.getInstance(this).getThemeColorAccent()) {
// // Theme colors changed, recreate the Activity
// recreate();
// }
// }
public int getThemeColorPrimary() {
return colorPrimary;
}
protected void setStatusBarTranslucent(boolean statusBarTranslucent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Util.setStatusBarTranslucent(getWindow(), statusBarTranslucent);
public int getThemeColorPrimaryDarker() {
return colorPrimaryDarker;
}
public int getThemeColorAccent() {
return colorAccent;
}
protected void setStatusBarTransparent() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
Util.setAllowDrawUnderStatusBar(getWindow());
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
Util.setStatusBarTranslucent(getWindow(), true);
}
protected final void setNavigationBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
getWindow().setNavigationBarColor(Util.shiftColorDown(color));
}
protected final void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
getWindow().setStatusBarColor(Util.shiftColorDown(color));
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final View statusBar = getWindow().getDecorView().getRootView().findViewById(R.id.status_bar);
if (statusBar != null) statusBar.setBackgroundColor(color);
}
}
protected abstract boolean shouldColorStatusBar();
protected abstract boolean shouldColorNavBar();
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected final void setStatusBarColor(int color, boolean forceSystemBarTint) {
if (!forceSystemBarTint && Util.isAtLeastLollipop()) {
getWindow().setStatusBarColor(color);
} else {
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintColor(color);
}
protected final void setNavigationBarThemeColor() {
setNavigationBarColor(colorPrimary);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected final void setShouldColorNavBar(boolean shouldColorNavBar) {
if (Util.isAtLeastLollipop()) {
if (shouldColorNavBar) {
final int primaryDark = PreferenceUtils.getInstance(this).getThemeColorPrimaryDarker();
getWindow().setNavigationBarColor(primaryDark);
} else {
getWindow().setNavigationBarColor(Color.BLACK);
}
}
protected final void setStatusBarThemeColor() {
setStatusBarColor(colorPrimary);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected final void setShouldColorStatusBar(boolean shouldColorStatusBar) {
if (shouldColorStatusBar) {
final int primaryDark = PreferenceUtils.getInstance(this).getThemeColorPrimaryDarker();
setStatusBarColor(primaryDark, false);
} else {
if (Util.isAtLeastLollipop()) {
getWindow().setStatusBarColor(Util.resolveColor(this, android.R.attr.statusBarColor));
} else {
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(false);
}
}
protected final void resetNavigationBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setNavigationBarColor(Util.resolveColor(this, android.R.attr.navigationBarColor));
}
protected final void resetStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setStatusBarColor(Util.resolveColor(this, android.R.attr.statusBarColor));
}
protected boolean overridesTaskColor() {
return false;
}
}

View file

@ -1,6 +1,5 @@
package com.kabouzeid.gramophone.ui.activities.tageditor;
import android.annotation.TargetApi;
import android.app.SearchManager;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@ -10,6 +9,7 @@ import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.Toolbar;
import android.util.Log;
@ -19,11 +19,11 @@ import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.ColorChooserDialog;
import com.kabouzeid.gramophone.misc.AppKeys;
import com.kabouzeid.gramophone.misc.SmallObservableScrollViewCallbacks;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
@ -32,7 +32,6 @@ import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.melnykov.fab.FloatingActionButton;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.nostra13.universalimageloader.core.ImageLoader;
@ -90,7 +89,6 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setStatusBarTranslucent(!Util.isAtLeastLollipop());
super.onCreate(savedInstanceState);
setContentView(getContentViewResId());
@ -113,16 +111,6 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected boolean shouldColorStatusBar() {
return false;
}
@Override
protected boolean shouldColorNavBar() {
return false;
}
private void initViews() {
fab = (FloatingActionButton) findViewById(R.id.fab);
scrollView = (ObservableScrollView) findViewById(R.id.observableScrollView);
@ -203,18 +191,19 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
save();
}
});
fab.setRippleColor(ThemeSingleton.get().positiveColor);
}
protected abstract void save();
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void resetColors() {
final int primaryColor = PreferenceUtils.getInstance(this).getThemeColorPrimary();
paletteColorPrimary = primaryColor;
observableScrollViewCallbacks.onScrollChanged(scrollView.getCurrentScrollY(), false, false);
setStatusBarColor(ColorChooserDialog.shiftColorDown(primaryColor), false);
setStatusBarColor(primaryColor);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(this).coloredNavigationBarTagEditorEnabled())
getWindow().setNavigationBarColor(primaryColor);
setNavigationBarColor(primaryColor);
notifyTaskColorChange(primaryColor);
}
@ -251,7 +240,7 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
return super.onOptionsItemSelected(item);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void setNoImageMode() {
isInNoImageMode = true;
image.setVisibility(View.GONE);
@ -264,10 +253,9 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
toolBar.setBackgroundColor(paletteColorPrimary);
header.setBackgroundColor(paletteColorPrimary);
int primaryDark = ColorChooserDialog.shiftColorDown(paletteColorPrimary);
setStatusBarColor(primaryDark, false);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(this).coloredNavigationBarTagEditorEnabled())
getWindow().setNavigationBarColor(primaryDark);
setStatusBarColor(paletteColorPrimary);
if (PreferenceUtils.getInstance(this).coloredNavigationBarTagEditorEnabled())
setNavigationBarColor(paletteColorPrimary);
}
protected void dataChanged() {
@ -301,7 +289,7 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
private void applyPalette(final Bitmap bitmap) {
Palette.from(bitmap)
.generate(new Palette.PaletteAsyncListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onGenerated(Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
@ -309,9 +297,9 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
final int vibrantColor = palette.getVibrantColor(DialogUtils.resolveColor(AbsTagEditorActivity.this, R.attr.default_bar_color));
paletteColorPrimary = vibrantColor;
observableScrollViewCallbacks.onScrollChanged(scrollView.getCurrentScrollY(), false, false);
setStatusBarColor(ColorChooserDialog.shiftColorDown(vibrantColor), false);
setStatusBarColor(vibrantColor);
if (Util.isAtLeastLollipop() && PreferenceUtils.getInstance(AbsTagEditorActivity.this).coloredNavigationBarTagEditorEnabled())
getWindow().setNavigationBarColor(vibrantColor);
setNavigationBarColor(vibrantColor);
notifyTaskColorChange(vibrantColor);
} else {
resetColors();

View file

@ -1,183 +0,0 @@
package com.kabouzeid.gramophone.ui.fragments;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.NavigationDrawerItemAdapter;
import com.kabouzeid.gramophone.misc.AppKeys;
import com.kabouzeid.gramophone.model.NavigationDrawerItem;
import java.util.ArrayList;
public class NavigationDrawerFragment extends Fragment {
public static final int NAVIGATION_DRAWER_HEADER = -1;
public static final int ABOUT_INDEX = 5;
public static final int SETTINGS_INDEX = 4;
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
public View fragmentRootView;
private NavigationDrawerCallbacks callbacks;
private NavigationDrawerItemAdapter drawerAdapter;
private DrawerLayout drawerLayout;
private RecyclerView drawerRecyclerView;
private Button headerButton;
private ImageView albumArt;
private TextView songTitle;
private TextView songArtist;
private boolean fromSavedInstanceState;
private boolean userLearnedDrawer;
private int checkedPosition = 0;
public NavigationDrawerFragment() {
}
public boolean isDrawerOpen() {
return drawerLayout != null && drawerLayout.isDrawerOpen(Gravity.START);
}
public void setUp(final DrawerLayout drawerLayout) {
this.drawerLayout = drawerLayout;
this.drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
if (!userLearnedDrawer && !fromSavedInstanceState) {
this.drawerLayout.openDrawer(Gravity.START);
userLearnedDrawer = true;
PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putBoolean(AppKeys.SP_USER_LEARNED_DRAWER, true).apply();
}
}
public TextView getSongArtist() {
return songArtist;
}
public ImageView getAlbumArtImageView() {
return albumArt;
}
public TextView getSongTitle() {
return songTitle;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
userLearnedDrawer = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(AppKeys.SP_USER_LEARNED_DRAWER, false);
if (savedInstanceState != null) {
setItemChecked(savedInstanceState.getInt(STATE_SELECTED_POSITION));
fromSavedInstanceState = true;
}
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
fragmentRootView = view;
super.onViewCreated(view, savedInstanceState);
initViews();
setUpViews();
}
private void initViews() {
drawerRecyclerView = (RecyclerView) fragmentRootView.findViewById(R.id.navigation_drawer_list);
final View drawerHeader = fragmentRootView.findViewById(R.id.header);
headerButton = (Button) drawerHeader.findViewById(R.id.header_clickable);
albumArt = (ImageView) drawerHeader.findViewById(R.id.album_art);
songTitle = (TextView) drawerHeader.findViewById(R.id.song_title);
songArtist = (TextView) drawerHeader.findViewById(R.id.song_artist);
}
private void setUpViews() {
headerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectItem(NAVIGATION_DRAWER_HEADER);
}
});
setUpListView();
}
private void setUpListView() {
final ArrayList<NavigationDrawerItem> navigationDrawerItems = new ArrayList<>();
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.songs), R.drawable.ic_audiotrack_white_24dp));
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.albums), R.drawable.ic_album_white_24dp));
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.artists), R.drawable.ic_person_white_24dp));
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.playlists), R.drawable.ic_queue_music_white_24dp));
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.action_settings), R.drawable.ic_settings_white_24dp));
navigationDrawerItems.add(new NavigationDrawerItem(getString(R.string.action_about), R.drawable.ic_help_white_24dp));
drawerAdapter = new NavigationDrawerItemAdapter(getActivity(), navigationDrawerItems, new NavigationDrawerItemAdapter.Callback() {
@Override
public void onItemSelected(int index) {
selectItem(index);
}
});
drawerRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
drawerRecyclerView.setAdapter(drawerAdapter);
}
private void selectItem(final int position) {
if (position != NAVIGATION_DRAWER_HEADER &&
position != ABOUT_INDEX && position != SETTINGS_INDEX) {
setItemChecked(position);
if (drawerLayout != null)
drawerLayout.closeDrawers();
}
if (callbacks != null)
callbacks.onNavigationDrawerItemSelected(position);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, checkedPosition);
}
@Override
public void onDetach() {
super.onDetach();
callbacks = null;
}
public void setItemChecked(final int position) {
if (drawerAdapter != null) {
drawerAdapter.setChecked(position);
checkedPosition = position;
}
}
public interface NavigationDrawerCallbacks {
void onNavigationDrawerItemSelected(int position);
}
}

View file

@ -5,7 +5,7 @@ import android.support.v4.app.Fragment;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble;
import com.kabouzeid.gramophone.util.Util;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
/**
* @author Karim Abou Zeid (kabouzeid)
@ -14,19 +14,15 @@ public abstract class AbsMainActivityFragment extends Fragment implements KabVie
private boolean areViewsEnabled;
protected int getTopPadding() {
final int norm = Util.getActionBarSize(getActivity()) +
getResources().getDimensionPixelSize(R.dimen.tab_height) +
getResources().getDimensionPixelSize(R.dimen.list_padding_vertical);
if (Util.isAtLeastKitKat() && !Util.isAtLeastLollipop()) {
if (Util.isInPortraitMode(getActivity()) || Util.isTablet(getActivity())) {
return norm + Util.getStatusBarHeight(getActivity());
}
}
return norm;
return getResources().getDimensionPixelSize(R.dimen.list_padding_vertical);
}
protected int getBottomPadding() {
return 0;
return getResources().getDimensionPixelSize(R.dimen.bottom_offset_fab_activity);
}
protected MainActivity getMainActivity() {
return (MainActivity) getActivity();
}
@Override

View file

@ -30,7 +30,7 @@ public class AlbumViewFragment extends AbsMainActivityRecyclerViewFragment {
@Override
protected RecyclerView.Adapter createAdapter() {
return new AlbumAdapter(getActivity());
return new AlbumAdapter(getMainActivity(), getMainActivity());
}
public void setColumns(int columns) {

View file

@ -22,6 +22,6 @@ public class ArtistViewFragment extends AbsMainActivityRecyclerViewFragment {
@Override
protected RecyclerView.Adapter createAdapter() {
return new ArtistAdapter(getActivity());
return new ArtistAdapter(getMainActivity(), getMainActivity());
}
}

View file

@ -2,7 +2,6 @@ package com.kabouzeid.gramophone.ui.fragments.mainactivityfragments;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
@ -41,7 +40,7 @@ public class PlaylistViewFragment extends AbsMainActivityRecyclerViewFragment {
@Override
protected RecyclerView.Adapter createAdapter() {
PlaylistAdapter adapter = new PlaylistAdapter((AppCompatActivity) getActivity());
PlaylistAdapter adapter = new PlaylistAdapter(getMainActivity(), getMainActivity());
View v = getView();
if (v != null) {
v.findViewById(android.R.id.empty).setVisibility(

View file

@ -1,6 +1,5 @@
package com.kabouzeid.gramophone.ui.fragments.mainactivityfragments;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
@ -26,6 +25,6 @@ public class SongViewFragment extends AbsMainActivityRecyclerViewFragment {
@Override
protected RecyclerView.Adapter createAdapter() {
return new SongAdapter((AppCompatActivity) getActivity());
return new SongAdapter(getMainActivity(), getMainActivity());
}
}

View file

@ -12,9 +12,11 @@ import android.widget.Toast;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.model.Song;
import java.util.ArrayList;
import java.util.List;
/**
@ -59,13 +61,26 @@ public class PlaylistsUtil {
// context.getContentResolver().delete(uri, null, null);
// }
public static void deletePlaylist(final Context context, final long playlistId) {
public static void deletePlaylists(final Context context, final long playlistId) {
final Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
String where = MediaStore.Audio.Playlists._ID + "=?";
String[] whereVal = {String.valueOf(playlistId)};
context.getContentResolver().delete(uri, where, whereVal);
Toast.makeText(context, context.getResources().getString(R.string.deleted_playlist_x,
getNameForPlaylist(context, playlistId)), Toast.LENGTH_SHORT).show();
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
}
public static void deletePlaylists(final Context context, final ArrayList<Playlist> playlists) {
final Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
final StringBuilder selection = new StringBuilder();
selection.append(MediaStore.Audio.Playlists._ID + " IN (");
for (int i = 0; i < playlists.size(); i++) {
selection.append(playlists.get(i).id);
if (i < playlists.size() - 1) {
selection.append(",");
}
}
selection.append(")");
context.getContentResolver().delete(uri, selection.toString(), null);
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
}
@ -131,20 +146,20 @@ public class PlaylistsUtil {
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
}
// public static void removeFromPlaylist(final Context context, final List<PlaylistSong> songs) {
// Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
// "external", songs.get(0).playlistId);
// String selectionArgs[] = new String[songs.size()];
// for (int i = 0; i < selectionArgs.length; i++) {
// selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList);
// }
// String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
// for (String selectionArg : selectionArgs) selection += "?, ";
// selection = selection.substring(0, selection.length() - 2) + ")";
//
// context.getContentResolver().delete(uri, selection, selectionArgs);
// App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
// }
public static void removeFromPlaylist(final Context context, final List<PlaylistSong> songs) {
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
"external", songs.get(0).playlistId);
String selectionArgs[] = new String[songs.size()];
for (int i = 0; i < selectionArgs.length; i++) {
selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList);
}
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
for (String selectionArg : selectionArgs) selection += "?, ";
selection = selection.substring(0, selection.length() - 2) + ")";
context.getContentResolver().delete(uri, selection, selectionArgs);
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
}
//
// public static int getSongCountForPlaylist(final Context context, final long playlistId) {
// Cursor c = context.getContentResolver().query(

View file

@ -6,7 +6,6 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.ColorChooserDialog;
import java.util.HashSet;
import java.util.Set;
@ -23,7 +22,7 @@ public final class PreferenceUtils {
public static final String ALBUM_SORT_ORDER = "album_sort_order";
public static final String ALBUM_SONG_SORT_ORDER = "album_song_sort_order";
public static final String SONG_SORT_ORDER = "song_sort_order";
public static final String ONLY_ON_WIFI = "auto_download_artist_images";
// public static final String ONLY_ON_WIFI = "auto_download_artist_images";
// public static final String DOWNLOAD_MISSING_ARTIST_IMAGES = "auto_download_artist_images";
public static final String COLORED_ALBUM_FOOTERS = "colored_album_footers";
public static final String COLORED_NAVIGATION_BAR = "colored_navigation_bar";
@ -33,10 +32,10 @@ public final class PreferenceUtils {
public static final String COLORED_NAVIGATION_BAR_PLAYIST = "colored_navigation_bar_playlist";
public static final String COLORED_NAVIGATION_BAR_TAG_EDITOR = "colored_navigation_bar_tag_editor";
public static final String COLORED_NAVIGATION_BAR_OTHER_SCREENS = "colored_navigation_bar_other_screens";
public static final String PLAYBACK_CONTROLLER_BOX = "playback_controller_card";
public static final String TRANSPARENT_TOOLBAR = "transparent_toolbar";
public static final String ALBUM_GRID_COLUMNS = "album_grid_columns";
public static final String ALBUM_GRID_COLUMNS_LAND = "album_grid_columns_land";
public static final String OPAQUE_TOOLBAR_NOW_PLAYING = "opaque_toolbar_now_playing";
public static final String FORCE_SQUARE_ALBUM_ART = "force_square_album_art";
private static PreferenceUtils sInstance;
@ -71,7 +70,7 @@ public final class PreferenceUtils {
}
public int getThemeColorPrimaryDarker() {
return ColorChooserDialog.shiftColorDown(getThemeColorPrimary());
return Util.shiftColorDown(getThemeColorPrimary());
}
@SuppressLint("CommitPrefEdits")
@ -80,7 +79,7 @@ public final class PreferenceUtils {
}
public int getThemeColorAccent() {
return mPreferences.getInt("accent_color", mContext.getResources().getColor(R.color.pink_500));
return mPreferences.getInt("accent_color", mContext.getResources().getColor(R.color.pink_A200));
}
@SuppressLint("CommitPrefEdits")
@ -136,7 +135,7 @@ public final class PreferenceUtils {
@SuppressLint("CommitPrefEdits")
private boolean coloredNavigationBarFor(String key) {
Set<String> defaultVals = new HashSet<>();
final Set<String> defaultVals = new HashSet<>();
defaultVals.add(COLORED_NAVIGATION_BAR_ALBUM);
defaultVals.add(COLORED_NAVIGATION_BAR_ARTIST);
defaultVals.add(COLORED_NAVIGATION_BAR_CURRENT_PLAYING);
@ -148,6 +147,7 @@ public final class PreferenceUtils {
mPreferences.edit().putStringSet(COLORED_NAVIGATION_BAR, defaultVals).commit();
try {
//noinspection ConstantConditions
return mPreferences.getStringSet(COLORED_NAVIGATION_BAR, defaultVals).contains(key);
} catch (NullPointerException e) {
return false;
@ -159,12 +159,12 @@ public final class PreferenceUtils {
// mPreferences.edit().putBoolean(COLORED_NAVIGATION_BAR_OTHER_SCREENS, coloredNavbar).commit();
// }
public final boolean playbackControllerBoxEnabled() {
return mPreferences.getBoolean(PLAYBACK_CONTROLLER_BOX, false);
public final boolean opaqueToolbarNowPlaying() {
return mPreferences.getBoolean(OPAQUE_TOOLBAR_NOW_PLAYING, false);
}
public final boolean transparentToolbar() {
return mPreferences.getBoolean(TRANSPARENT_TOOLBAR, false);
public final boolean forceAlbumArtSquared() {
return mPreferences.getBoolean(FORCE_SQUARE_ALBUM_ART, false);
}
// public final boolean downloadMissingArtistImages() {

View file

@ -3,11 +3,14 @@ package com.kabouzeid.gramophone.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
@ -106,6 +109,12 @@ public class Util {
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
public static void setAllowDrawUnderStatusBar(Window window) {
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
// public static boolean isOnline(final Context context) {
// if (context == null)
// return false;
@ -201,4 +210,32 @@ public class Util {
}
return drawable;
}
public static int getOpaqueColor(@ColorInt int color) {
return color | 0xFF000000;
}
public static int getColorWithAlpha(float alpha, int baseColor) {
int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24;
int rgb = 0x00ffffff & baseColor;
return a + rgb;
}
@SuppressWarnings("ResourceType")
public static int shiftColorDown(int color) {
int alpha = Color.alpha(color);
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.9f; // value component
return (alpha << 24) + (0x00ffffff & Color.HSVToColor(hsv));
}
public static ColorStateList getEmptyColorStateList(int color) {
return new ColorStateList(
new int[][]{
new int[]{}
},
new int[]{color}
);
}
}

View file

@ -13,12 +13,15 @@ import android.widget.CheckBox;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.internal.MDTintHelper;
import java.lang.reflect.Field;
import hugo.weaving.DebugLog;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
@ -84,6 +87,22 @@ public class ViewUtil {
animator.start();
}
@DebugLog
public static void animateTextColor(final TextView v, final int startColor, final int endColor) {
animateTextColor(v, startColor, endColor, DEFAULT_COLOR_ANIMATION_DURATION);
}
public static void animateTextColor(final TextView v, final int startColor, final int endColor, final int duration) {
ObjectAnimator animator = ObjectAnimator.ofObject(v, "textColor",
new ArgbEvaluator(), startColor, endColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
animator.setInterpolator(new PathInterpolator(0.4f, 0f, 1f, 1f));
}
animator.setDuration(duration);
animator.start();
}
public static void setBackgroundAlpha(View view, float alpha, int baseColor) {
int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24;
int rgb = 0x00ffffff & baseColor;

View file

@ -13,8 +13,9 @@ import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.util.Util;
public class CircleView extends FrameLayout {
public class ColorView extends FrameLayout {
private final Bitmap mCheck;
private final Paint paint;
@ -22,19 +23,19 @@ public class CircleView extends FrameLayout {
private Paint paintCheck;
private final int borderWidth;
public CircleView(Context context) {
public ColorView(Context context) {
this(context, null, 0);
}
public CircleView(Context context, AttributeSet attrs) {
public ColorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
public ColorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final int checkSize = (int) context.getResources().getDimension(R.dimen.circle_view_check);
mCheck = getResizedBitmap(BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_check_white_24dp), checkSize, checkSize);
R.drawable.ic_checkbox_marked_circle_outline_white_24dp), checkSize, checkSize);
borderWidth = (int) getResources().getDimension(R.dimen.circle_view_border);
paint = new Paint();
@ -42,7 +43,6 @@ public class CircleView extends FrameLayout {
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
paintBorder.setColor(Color.BLACK);
setWillNotDraw(false);
}
@ -64,12 +64,7 @@ public class CircleView extends FrameLayout {
@Override
public void setBackgroundColor(int color) {
paint.setColor(color);
requestLayout();
invalidate();
}
public void setBorderColor(int color) {
paintBorder.setColor(color);
paintBorder.setColor(Util.shiftColorDown(color));
requestLayout();
invalidate();
}

View file

@ -0,0 +1,30 @@
package com.kabouzeid.gramophone.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class HeightFitSquareImageView extends ImageView {
public HeightFitSquareImageView(Context context) {
super(context);
}
public HeightFitSquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HeightFitSquareImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//noinspection SuspiciousNameCombination
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}
}

View file

@ -0,0 +1,30 @@
package com.kabouzeid.gramophone.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class HeightWidthFitSquareImageView extends ImageView {
public HeightWidthFitSquareImageView(Context context) {
super(context);
}
public HeightWidthFitSquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HeightWidthFitSquareImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int small = Math.min(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(small, small);
}
}

View file

@ -44,8 +44,6 @@ public class PlayPauseDrawable extends Drawable {
private float width;
private float height;
private final float fallBackWidth;
private final float fallBackHeight;
private float progress;
private boolean isPlay;
@ -61,8 +59,6 @@ public class PlayPauseDrawable extends Drawable {
pauseBarWidth = res.getDimensionPixelSize(R.dimen.pause_bar_width);
pauseBarHeight = res.getDimensionPixelSize(R.dimen.pause_bar_height);
pauseBarDistance = res.getDimensionPixelSize(R.dimen.pause_bar_distance);
fallBackWidth = res.getDimensionPixelSize(R.dimen.fab_icon_bound_width);
fallBackHeight = res.getDimensionPixelSize(R.dimen.fab_icon_bound_height);
}
@Override
@ -71,9 +67,6 @@ public class PlayPauseDrawable extends Drawable {
if (bounds.width() > 0 && bounds.height() > 0) {
width = bounds.width();
height = bounds.height();
} else {
width = fallBackWidth;
height = fallBackHeight;
}
}

View file

@ -1,126 +0,0 @@
package com.kabouzeid.gramophone.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.kabouzeid.gramophone.R;
/**
* A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
* (status and navigation bars, overlay action bars).
*/
public class ScrimInsetsFrameLayout extends FrameLayout {
private Drawable mInsetForeground;
private Rect mInsets;
private Rect mTempRect = new Rect();
private OnInsetsCallback mOnInsetsCallback;
public ScrimInsetsFrameLayout(Context context) {
super(context);
init(context, null, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ScrimInsetsView, defStyle, 0);
if (a == null) {
return;
}
mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground);
a.recycle();
setWillNotDraw(true);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
mInsets = new Rect(insets);
setWillNotDraw(mInsetForeground == null);
ViewCompat.postInvalidateOnAnimation(this);
if (mOnInsetsCallback != null) {
mOnInsetsCallback.onInsetsChanged(insets);
}
return true; // consume insets
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
int width = getWidth();
int height = getHeight();
if (mInsets != null && mInsetForeground != null) {
int sc = canvas.save();
canvas.translate(getScrollX(), getScrollY());
// Top
mTempRect.set(0, 0, width, mInsets.top);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Bottom
mTempRect.set(0, height - mInsets.bottom, width, height);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Left
mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
// Right
mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
mInsetForeground.setBounds(mTempRect);
mInsetForeground.draw(canvas);
canvas.restoreToCount(sc);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(this);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mInsetForeground != null) {
mInsetForeground.setCallback(null);
}
}
/**
* Allows the calling container to specify a callback for custom processing when insets change (i.e. when
* {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
* UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
* clipToPadding to false.
*/
public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
mOnInsetsCallback = onInsetsCallback;
}
public static interface OnInsetsCallback {
public void onInsetsChanged(Rect insets);
}
}

View file

@ -0,0 +1,44 @@
package com.kabouzeid.gramophone.views;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SquareIfPlaceImageView extends ImageView {
private boolean forceSquare = false;
public SquareIfPlaceImageView(Context context) {
super(context);
}
public SquareIfPlaceImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareIfPlaceImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int small = Math.min(widthMeasureSpec, heightMeasureSpec);
final int large = Math.max(widthMeasureSpec, heightMeasureSpec);
if (forceSquare) super.onMeasure(small, small);
else if (View.MeasureSpec.getSize(large) > View.MeasureSpec.getSize(small) * 1.5)
super.onMeasure(small, small);
else super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void forceSquare(boolean force) {
if (forceSquare != force) {
forceSquare = force;
invalidate();
}
}
}

View file

@ -7,17 +7,17 @@ import android.widget.ImageView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SquareImageView extends ImageView {
public class WidthFitSquareImageView extends ImageView {
public SquareImageView(Context context) {
public WidthFitSquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
public WidthFitSquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
public WidthFitSquareImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:height="12dp"
android:width="12dp"/>
android:height="20dp"
android:width="3dp" />
<solid
android:color="@color/materialmusic_accent_color"/>
android:color="@color/black" />
</shape>

View file

@ -1,227 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kabouzeid.gramophone.ui.activities.AlbumDetailActivity$PlaceholderFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="centerCrop"
android:src="@drawable/default_album_art"
android:transitionName="@string/transition_album_cover"
tools:ignore="ContentDescription,UnusedAttribute" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/artist_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/footer"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/footer"
android:background="@drawable/shadow_up" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/footer"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/song_current_progress"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:fontFamily="sans-serif-medium"
android:gravity="bottom|left|start"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@color/white"
android:textSize="16sp"
tools:ignore="RtlHardcoded" />
<TextView
android:id="@+id/song_total_time"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:fontFamily="sans-serif"
android:gravity="bottom|right|end"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@color/white"
android:textSize="16sp"
tools:ignore="RtlHardcoded" />
</LinearLayout>
<LinearLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?default_bar_color"
android:elevation="@dimen/toolbar_elevation"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="vertical"
android:transitionName="@string/transition_album_text"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/song_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="?attr/title_text_color" />
<TextView
android:id="@+id/song_artist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
android:textColor="?attr/caption_text_color" />
</LinearLayout>
<RelativeLayout
android:id="@+id/media_controller_placeholder"
android:layout_width="match_parent"
android:layout_height="88dp"
android:layout_gravity="bottom"
android:layout_margin="16dp"
android:background="?attr/music_controller_container_color"
android:elevation="1dp"
tools:ignore="UnusedAttribute">
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/media_controller_container"
android:layout_width="match_parent"
android:layout_height="88dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="16dp"
android:background="?attr/music_controller_container_color"
android:elevation="@dimen/toolbar_elevation"
tools:ignore="ContentDescription,UnusedAttribute">
<com.melnykov.fab.FloatingActionButton
android:id="@+id/fab"
style="@style/PlayPauseFab"
android:layout_centerInParent="true" />
<ImageButton
android:id="@+id/prev_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_centerVertical="true"
android:layout_marginEnd="-4dp"
android:layout_marginRight="-4dp"
android:layout_toLeftOf="@+id/fab"
android:layout_toStartOf="@+id/fab"
android:background="?round_selector"
android:padding="14dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_previous_white_48dp" />
<ImageButton
android:id="@+id/next_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_centerVertical="true"
android:layout_marginLeft="-4dp"
android:layout_marginStart="-4dp"
android:layout_toEndOf="@+id/fab"
android:layout_toRightOf="@+id/fab"
android:background="?round_selector"
android:padding="14dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_skip_next_white_48dp" />
<ImageButton
android:id="@+id/repeat_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:background="?round_selector"
android:padding="14dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_repeat_grey600_48dp" />
<ImageButton
android:id="@+id/shuffle_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="?round_selector"
android:padding="14dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_shuffle_grey600_48dp" />
</RelativeLayout>
<SeekBar
android:id="@+id/progress_slider"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/footer"
android:elevation="2dp"
android:padding="0dp"
android:progressTint="@color/materialmusic_accent_color"
android:thumbTint="@color/materialmusic_accent_color_darker"
tools:ignore="UnusedAttribute" />
</RelativeLayout>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:layout_marginTop="@dimen/statusMargin"
android:background="@android:color/transparent" />
</FrameLayout>

View file

@ -3,14 +3,27 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/album_art"
<FrameLayout
android:background="?android:colorBackground"
android:layout_width="match_parent"
android:layout_height="@dimen/header_image_height"
android:scaleType="centerCrop"
android:src="@drawable/default_album_art"
android:transitionName="@string/transition_album_cover"
tools:ignore="ContentDescription,UnusedAttribute" />
android:layout_height="@dimen/header_image_height">
<ImageView
android:id="@+id/album_art_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<com.kabouzeid.gramophone.views.SquareIfPlaceImageView
android:id="@+id/album_art"
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_cover"
tools:ignore="ContentDescription,UnusedAttribute" />
</FrameLayout>
<View
android:id="@+id/list_background"
@ -61,25 +74,30 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:id="@+id/statusBar"
android:layout_width="match_parent"
android:layout_height="@dimen/statusMargin"
android:background="@android:color/transparent" />
<include layout="@layout/status_bar" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@android:color/transparent" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</FrameLayout>
</LinearLayout>
<com.melnykov.fab.FloatingActionButton
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
style="@style/PlayPauseFab"
android:layout_gravity="right|end"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
tools:ignore="RtlHardcoded" />
android:layout_gravity="end|right|bottom"
android:layout_margin="16dp" />
</FrameLayout>

View file

@ -15,7 +15,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kabouzeid.gramophone.views.SquareImageView
<com.kabouzeid.gramophone.views.WidthFitSquareImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -159,7 +159,7 @@
android:gravity="start|left"
tools:ignore="RtlHardcoded" />
<com.melnykov.fab.FloatingActionButton
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
style="@style/PlayPauseFab"
android:layout_gravity="bottom|right|end"

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