diff --git a/app/build.gradle b/app/build.gradle index 98794047..b597e35a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java new file mode 100644 index 00000000..ed8c11f3 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/AbsMultiSelectAdapter.java @@ -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 extends RecyclerView.Adapter implements MaterialCab.Callback { + private final CabHolder cabHolder; + private MaterialCab cab; + private ArrayList 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 selection); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java index 9d263429..cd9f06b0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumAdapter.java @@ -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 { +public class AlbumAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumAdapter.class.getSimpleName(); - private final Activity activity; + private final AppCompatActivity activity; private boolean usePalette; private List dataSet; @@ -53,6 +66,10 @@ public class AlbumAdapter extends RecyclerView.Adapter 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 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 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 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 getSongList(List albums) { + final ArrayList 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 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 } 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); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java index 97e56291..d3a7d7b7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAdapter.java @@ -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 { - protected final Activity activity; +public class ArtistAdapter extends AbsMultiSelectAdapter { + protected final AppCompatActivity activity; protected List 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 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 getSongList(List artists) { + final ArrayList 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; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java index 720cd6a5..1251649c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/ArtistAlbumAdapter.java @@ -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 { +public class ArtistAlbumAdapter extends AbsMultiSelectAdapter { 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 dataSet; + private final AppCompatActivity activity; + private ArrayList dataSet; private final int listMargin; + public ArtistAlbumAdapter(AppCompatActivity activity, ArrayList 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 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 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 getSongList(List albums) { + final ArrayList 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 objects) { - this.activity = activity; - dataSet = objects; - listMargin = activity.getResources().getDimensionPixelSize(R.dimen.default_item_margin); - } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/NavigationDrawerItemAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/NavigationDrawerItemAdapter.java deleted file mode 100644 index bc49146d..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/NavigationDrawerItemAdapter.java +++ /dev/null @@ -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 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 mItems; - private final Callback mCallback; - - public interface Callback { - void onItemSelected(int index); - } - - public NavigationDrawerItemAdapter(Context context, ArrayList 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(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java index f9162ed6..d76c6893 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java @@ -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 { +public class PlaylistAdapter extends AbsMultiSelectAdapter { public static final String TAG = PlaylistAdapter.class.getSimpleName(); protected final AppCompatActivity activity; protected List 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 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 getSongList(List playlists) { + final ArrayList 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 { +public class AlbumSongAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumSongAdapter.class.getSimpleName(); protected final AppCompatActivity activity; - protected final ArrayList dataSet; + protected ArrayList dataSet; - public AlbumSongAdapter(AppCompatActivity activity, ArrayList objects) { + public AlbumSongAdapter(AppCompatActivity activity, ArrayList objects, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_media_selection); this.activity = activity; dataSet = objects; } + public void updateDataSet(ArrayList 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 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; } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java index e49eca39..e685f03a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/ArtistSongAdapter.java @@ -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 { +public class ArtistSongAdapter extends ArrayAdapter implements MaterialCab.Callback { + + private final CabHolder cabHolder; + private MaterialCab cab; + private ArrayList dataSet; + private ArrayList checked; private final AppCompatActivity activity; - public ArtistSongAdapter(AppCompatActivity activity, List songs) { + public ArtistSongAdapter(AppCompatActivity activity, ArrayList 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 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 { 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 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; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java index f97cab2a..4126a08f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/PlaylistSongAdapter.java @@ -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 { +public class PlaylistSongAdapter extends AbsMultiSelectAdapter { public static final String TAG = AlbumSongAdapter.class.getSimpleName(); protected final AppCompatActivity activity; - protected final ArrayList dataSet; + protected ArrayList dataSet; - public PlaylistSongAdapter(AppCompatActivity activity, ArrayList objects) { + public PlaylistSongAdapter(AppCompatActivity activity, ArrayList objects, @Nullable CabHolder cabHolder) { + super(cabHolder, R.menu.menu_playlists_songs_selection); this.activity = activity; dataSet = objects; } + public void updateDataSet(ArrayList 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 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) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST"); + break; + case R.id.action_add_to_current_playing: + //noinspection unchecked + MusicPlayerRemote.enqueue((ArrayList) (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) (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) (List) dataSet, getAdapterPosition(), true); + } + } + + @Override + public boolean onLongClick(View view) { + toggleChecked(getAdapterPosition()); + return true; } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java index badb0ba9..5da11120 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java +++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/songadapter/SongAdapter.java @@ -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 { +public class SongAdapter extends AbsMultiSelectAdapter 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 { protected final AppCompatActivity activity; protected ArrayList 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 { .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 { 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 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 { 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); diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ColorChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ColorChooserDialog.java index 9edd21df..8928c24b 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ColorChooserDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ColorChooserDialog.java @@ -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); diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java new file mode 100644 index 00000000..3e0b3c62 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteFromPlaylistDialog.java @@ -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 list = new ArrayList<>(); + list.add(song); + return create(list); + } + + public static DeleteFromPlaylistDialog create(ArrayList 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 songs = (ArrayList) 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(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java index a448924f..b9db377e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java @@ -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 list = new ArrayList<>(); + list.add(playlist); + return create(list); + } + + public static DeletePlaylistDialog create(ArrayList 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 playlists = (ArrayList) 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(); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java index 9f5e8619..f27d6ef7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java @@ -36,7 +36,7 @@ public class DeleteSongsDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { //noinspection unchecked - ArrayList songs = (ArrayList) getArguments().getSerializable("songs"); + final ArrayList songs = (ArrayList) 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 songs = (ArrayList) getArguments().getSerializable("songs"); MusicUtil.deleteTracks(getActivity(), songs); } }).build(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java index 508a471d..fbf0e9ee 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MenuItemClickHelper.java @@ -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; diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java index fdf19e15..eb506f61 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java @@ -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 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); diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/BlurProcess.java b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/BlurProcess.java new file mode 100644 index 00000000..cce072b3 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/BlurProcess.java @@ -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); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/JavaBlurProcess.java b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/JavaBlurProcess.java new file mode 100644 index 00000000..cc5a7336 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/JavaBlurProcess.java @@ -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. + *

+ * 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. + *

+ * 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 + * http://www.neo-tech.es + *

+ * Author of the original algorithm: Mario Klingemann + *

+ * 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 horizontal = new ArrayList(cores); + ArrayList vertical = new ArrayList(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 { + 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; + } + + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/StackBlurManager.java b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/StackBlurManager.java new file mode 100644 index 00000000..76adef03 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/bitmapblur/StackBlurManager.java @@ -0,0 +1,89 @@ +/** + * StackBlur v1.0 for Android + * + * @Author: Enrique López Mañas + * http://www.lopez-manas.com + *

+ * Author of the original algorithm: Mario Klingemann + *

+ * 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. + *

+ * 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; + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java new file mode 100644 index 00000000..cf836d88 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java @@ -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); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java index b7a13887..24cdfd55 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java @@ -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()); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java index a931616c..df5d1d11 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumSongLoader.java @@ -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, diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java index eaa82d0d..4e3a8930 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistAlbumLoader.java @@ -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 getArtistAlbumList(final Context context, final int artistId) { + public static ArrayList getArtistAlbumList(final Context context, final int artistId) { Cursor cursor = makeArtistAlbumCursor(context, artistId); - List albums = new ArrayList<>(); + ArrayList 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()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java index 3d84ef23..2a68191c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/ArtistSongLoader.java @@ -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, diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java index 619daf1e..5b201d99 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/PlaylistSongLoader.java @@ -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); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java index 9c7e00b5..0bc8607c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/SongLoader.java @@ -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(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/misc/DragSortRecycler.java b/app/src/main/java/com/kabouzeid/gramophone/misc/DragSortRecycler.java index 4c5bd829..1dae9de7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/misc/DragSortRecycler.java +++ b/app/src/main/java/com/kabouzeid/gramophone/misc/DragSortRecycler.java @@ -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; diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Album.java b/app/src/main/java/com/kabouzeid/gramophone/model/Album.java index b674c284..5ebf3844 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Album.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Album.java @@ -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; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java b/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java index 48911ec6..51a1eba7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Artist.java @@ -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; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java b/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java index 8905c4cf..dedc8b2f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Playlist.java @@ -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; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java b/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java index e746a877..8de0beba 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/PlaylistSong.java @@ -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; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/Song.java b/app/src/main/java/com/kabouzeid/gramophone/model/Song.java index 4497f70b..4543586d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/Song.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/Song.java @@ -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; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/UIPreferenceChangedEvent.java b/app/src/main/java/com/kabouzeid/gramophone/model/UIPreferenceChangedEvent.java index 7fab264e..b1fea376 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/UIPreferenceChangedEvent.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/UIPreferenceChangedEvent.java @@ -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; diff --git a/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java b/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java index 60b1d7f2..9748b77d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java +++ b/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java @@ -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); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java index 20427782..53c92f6a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java @@ -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 songs) { + playingQueue.addAll(position, songs); + originalPlayingQueue.addAll(position, songs); + saveState(); + } + + public void addSongs(List 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); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java index 8bc381d4..b173e8d4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java @@ -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; *

* 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 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 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(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java index 02a3a22b..8a159012 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java @@ -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. *

* 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 songs; + private ArrayList 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 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 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(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java index 1de1e71e..b28529ba 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java @@ -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) + ) + })); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java index f784b720..48c12114 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java @@ -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); } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java index 7eacb053..81b80c1f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java @@ -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 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 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(); + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SearchActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SearchActivity.java index da7a2d5e..09d593f2 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SearchActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SearchActivity.java @@ -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 diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java index ed295c82..e04bd5c9 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java @@ -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; } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java index 293bb12d..755bea24 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java @@ -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: diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java index b635d5c7..8ff515a9 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java @@ -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() { + + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java index 1e34a122..a4fd4d8b 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java @@ -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! - *

- * Instructions: - *

- * 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()) - *

- * 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; } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/tageditor/AbsTagEditorActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/tageditor/AbsTagEditorActivity.java index efc49d4d..840680e0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/tageditor/AbsTagEditorActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/tageditor/AbsTagEditorActivity.java @@ -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(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/NavigationDrawerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/NavigationDrawerFragment.java deleted file mode 100644 index 2bed3859..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/NavigationDrawerFragment.java +++ /dev/null @@ -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 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); - } -} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java index 5ff364f9..4dbad6ed 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AbsMainActivityFragment.java @@ -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 diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java index 69cdb518..bbe38327 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/AlbumViewFragment.java @@ -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) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java index 0c7f0cd4..8f03f74c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/ArtistViewFragment.java @@ -22,6 +22,6 @@ public class ArtistViewFragment extends AbsMainActivityRecyclerViewFragment { @Override protected RecyclerView.Adapter createAdapter() { - return new ArtistAdapter(getActivity()); + return new ArtistAdapter(getMainActivity(), getMainActivity()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java index 78230653..8cc0bbfc 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/PlaylistViewFragment.java @@ -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( diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java index 1697b487..15a96ed8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/mainactivityfragments/SongViewFragment.java @@ -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()); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java index 8ed31d68..0a2be896 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PlaylistsUtil.java @@ -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 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 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 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( diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java index a705ed8d..41af08b1 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java @@ -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 defaultVals = new HashSet<>(); + final Set 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() { diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/Util.java b/app/src/main/java/com/kabouzeid/gramophone/util/Util.java index 1afe5243..d883e4db 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/Util.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/Util.java @@ -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} + ); + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java index bca1878c..fc7cd40c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java @@ -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; diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/CircleView.java b/app/src/main/java/com/kabouzeid/gramophone/views/ColorView.java similarity index 88% rename from app/src/main/java/com/kabouzeid/gramophone/views/CircleView.java rename to app/src/main/java/com/kabouzeid/gramophone/views/ColorView.java index cb57978d..89e7976e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/views/CircleView.java +++ b/app/src/main/java/com/kabouzeid/gramophone/views/ColorView.java @@ -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(); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/HeightFitSquareImageView.java b/app/src/main/java/com/kabouzeid/gramophone/views/HeightFitSquareImageView.java new file mode 100644 index 00000000..0ded0ba1 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/views/HeightFitSquareImageView.java @@ -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); + } + +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/HeightWidthFitSquareImageView.java b/app/src/main/java/com/kabouzeid/gramophone/views/HeightWidthFitSquareImageView.java new file mode 100644 index 00000000..93872632 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/views/HeightWidthFitSquareImageView.java @@ -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); + } + +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/PlayPauseDrawable.java b/app/src/main/java/com/kabouzeid/gramophone/views/PlayPauseDrawable.java index ca507e4c..24740570 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/views/PlayPauseDrawable.java +++ b/app/src/main/java/com/kabouzeid/gramophone/views/PlayPauseDrawable.java @@ -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; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/ScrimInsetsFrameLayout.java b/app/src/main/java/com/kabouzeid/gramophone/views/ScrimInsetsFrameLayout.java deleted file mode 100644 index d76318a5..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/views/ScrimInsetsFrameLayout.java +++ /dev/null @@ -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); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/SquareIfPlaceImageView.java b/app/src/main/java/com/kabouzeid/gramophone/views/SquareIfPlaceImageView.java new file mode 100644 index 00000000..ce034fd8 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/views/SquareIfPlaceImageView.java @@ -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(); + } + } + +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/SquareImageView.java b/app/src/main/java/com/kabouzeid/gramophone/views/WidthFitSquareImageView.java similarity index 65% rename from app/src/main/java/com/kabouzeid/gramophone/views/SquareImageView.java rename to app/src/main/java/com/kabouzeid/gramophone/views/WidthFitSquareImageView.java index 816cb3ef..3200fe24 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/views/SquareImageView.java +++ b/app/src/main/java/com/kabouzeid/gramophone/views/WidthFitSquareImageView.java @@ -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); } diff --git a/app/src/main/res/drawable-hdpi/ic_checkbox_marked_circle_outline_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_checkbox_marked_circle_outline_white_24dp.png new file mode 100644 index 00000000..d8ec2d08 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_checkbox_marked_circle_outline_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..5e89821e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..e466600a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..7efdfab6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_repeat_grey600_48dp.png b/app/src/main/res/drawable-hdpi/ic_repeat_grey600_48dp.png deleted file mode 100644 index 6a890612..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_repeat_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_shuffle_grey600_48dp.png b/app/src/main/res/drawable-hdpi/ic_shuffle_grey600_48dp.png deleted file mode 100644 index a079e10d..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_shuffle_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_checkbox_marked_circle_outline_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_checkbox_marked_circle_outline_white_24dp.png new file mode 100644 index 00000000..1f4969a0 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_checkbox_marked_circle_outline_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..8d48b838 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..a86bc505 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..1aeb991a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_repeat_grey600_48dp.png b/app/src/main/res/drawable-mdpi/ic_repeat_grey600_48dp.png deleted file mode 100644 index 3d0e2754..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_repeat_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_shuffle_grey600_48dp.png b/app/src/main/res/drawable-mdpi/ic_shuffle_grey600_48dp.png deleted file mode 100644 index 4da2fee0..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_shuffle_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_checkbox_marked_circle_outline_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_checkbox_marked_circle_outline_white_24dp.png new file mode 100644 index 00000000..101e2a3c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_checkbox_marked_circle_outline_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..3c9e1718 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..aa874a65 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..6ab40bc4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_repeat_grey600_48dp.png b/app/src/main/res/drawable-xhdpi/ic_repeat_grey600_48dp.png deleted file mode 100644 index bf33f287..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_repeat_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_shuffle_grey600_48dp.png b/app/src/main/res/drawable-xhdpi/ic_shuffle_grey600_48dp.png deleted file mode 100644 index 1c17d675..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_shuffle_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png new file mode 100644 index 00000000..d948a7c2 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..5d2e8ea3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..82e0ee1f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..844e8c4e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_repeat_grey600_48dp.png b/app/src/main/res/drawable-xxhdpi/ic_repeat_grey600_48dp.png deleted file mode 100644 index f0935d06..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_repeat_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_48dp.png b/app/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_48dp.png deleted file mode 100644 index de8e0c3a..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_shuffle_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png b/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png new file mode 100644 index 00000000..5dba3bb8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check_white_96dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png new file mode 100644 index 00000000..fdd58427 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_checkbox_marked_circle_outline_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png new file mode 100644 index 00000000..e7b2514d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png new file mode 100644 index 00000000..ae4cdc5b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_playlist_add_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png new file mode 100644 index 00000000..cffe4fa8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_queue_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_repeat_grey600_48dp.png b/app/src/main/res/drawable-xxxhdpi/ic_repeat_grey600_48dp.png deleted file mode 100755 index 237cd896..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_repeat_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_48dp.png b/app/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_48dp.png deleted file mode 100755 index a5ab732d..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_shuffle_grey600_48dp.png and /dev/null differ diff --git a/app/src/main/res/drawable/slider_thumb.xml b/app/src/main/res/drawable/slider_thumb.xml index a69f10ab..4c099c65 100644 --- a/app/src/main/res/drawable/slider_thumb.xml +++ b/app/src/main/res/drawable/slider_thumb.xml @@ -1,8 +1,9 @@ - + + android:height="20dp" + android:width="3dp" /> + android:color="@color/black" /> \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_music_controller.xml b/app/src/main/res/layout-land/activity_music_controller.xml deleted file mode 100644 index 13c9856c..00000000 --- a/app/src/main/res/layout-land/activity_music_controller.xml +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_album_detail.xml b/app/src/main/res/layout/activity_album_detail.xml index 9623d4ac..5aabbe5d 100644 --- a/app/src/main/res/layout/activity_album_detail.xml +++ b/app/src/main/res/layout/activity_album_detail.xml @@ -3,14 +3,27 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="@dimen/header_image_height"> + + + + + - + - + + + + + + + - + android:layout_gravity="end|right|bottom" + android:layout_margin="16dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album_tag_editor.xml b/app/src/main/res/layout/activity_album_tag_editor.xml index 6947a576..fccab64c 100644 --- a/app/src/main/res/layout/activity_album_tag_editor.xml +++ b/app/src/main/res/layout/activity_album_tag_editor.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - + android:layout_height="@dimen/header_image_height"> + + + + + - + - + + + + + + + - + android:layout_gravity="end|right|bottom" + android:layout_margin="16dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4386dc78..6a400a06 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,100 +8,67 @@ android:fitsSystemWindows="true" tools:context=".DrawerActivity"> - + + + + + + + + + + + + + + + + + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + - + - - - - - - - - - - - - - - - - - - - - - - - + app:menu="@menu/menu_drawer" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_music_controller.xml b/app/src/main/res/layout/activity_music_controller.xml index 2619b141..90a87729 100644 --- a/app/src/main/res/layout/activity_music_controller.xml +++ b/app/src/main/res/layout/activity_music_controller.xml @@ -1,207 +1,218 @@ - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="com.kabouzeid.gramophone.ui.activities.MusicControllerActivity"> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:orientation="vertical"> - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_playlist_detail.xml b/app/src/main/res/layout/activity_playlist_detail.xml index 9842ce10..390f1872 100644 --- a/app/src/main/res/layout/activity_playlist_detail.xml +++ b/app/src/main/res/layout/activity_playlist_detail.xml @@ -1,18 +1,27 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:orientation="vertical"> - + + + + + + + @@ -36,18 +45,10 @@ android:textColor="?android:textColorSecondary" android:textSize="@dimen/empty_text_size" /> - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_song_tag_editor.xml b/app/src/main/res/layout/activity_song_tag_editor.xml index 875ac5ee..e00c88e4 100644 --- a/app/src/main/res/layout/activity_song_tag_editor.xml +++ b/app/src/main/res/layout/activity_song_tag_editor.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - - - - - - - - - - -