Great progress with the new now playing screen. Almost done now.

This commit is contained in:
Karim Abou Zeid 2015-12-12 01:16:48 +01:00
commit 0de4590a87
32 changed files with 261 additions and 103 deletions

View file

@ -35,7 +35,7 @@ public abstract class AbsMultiSelectAdapter<VH extends RecyclerView.ViewHolder,
this.menuRes = menuRes;
}
protected void toggleChecked(final int position) {
protected boolean toggleChecked(final int position) {
if (cabHolder != null) {
openCabIfNecessary();
@ -47,7 +47,10 @@ public abstract class AbsMultiSelectAdapter<VH extends RecyclerView.ViewHolder,
if (size <= 0) cab.finish();
else if (size == 1) cab.setTitle(checked.get(0).toString());
else if (size > 1) cab.setTitle(context.getString(R.string.x_selected, size));
return true;
}
return false;
}
private void openCabIfNecessary() {

View file

@ -16,7 +16,7 @@ import butterknife.ButterKnife;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class MediaEntryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public class MediaEntryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
@Nullable
@Bind(R.id.image)
public ImageView image;

View file

@ -15,20 +15,75 @@ import java.util.ArrayList;
* @author Karim Abou Zeid (kabouzeid)
*/
public class PlayingQueueAdapter extends SongAdapter {
private static final int HISTORY = 0;
private static final int CURRENT = 1;
private static final int UP_NEXT = 2;
private int current;
public PlayingQueueAdapter(AppCompatActivity activity, ArrayList<Song> dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
@Override
protected SongAdapter.ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
public void onBindViewHolder(@NonNull SongAdapter.ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder.imageText != null) {
holder.imageText.setVisibility(View.VISIBLE);
holder.imageText.setText("" + (position - current));
}
if (holder.image != null) {
holder.image.setVisibility(View.GONE);
}
if (holder.getItemViewType() == HISTORY) {
setAlpha(holder, 0.5f);
} else if (holder.getItemViewType() == CURRENT) {
holder.itemView.setActivated(true);
}
}
public class ViewHolder extends SongAdapter.ViewHolder {
@Override
public int getItemViewType(int position) {
if (position < current) {
return HISTORY;
} else if (position > current) {
return UP_NEXT;
}
return CURRENT;
}
public ViewHolder(@NonNull View itemView) {
super(itemView);
image = null;
@Override
protected void loadAlbumCover(Song song, ViewHolder holder) {
//super.loadAlbumCover(song, holder);
}
public void swapDataSet(ArrayList<Song> dataSet, int position) {
this.dataSet = dataSet;
current = position;
notifyDataSetChanged();
}
public void setCurrent(int current) {
this.current = current;
notifyDataSetChanged();
}
protected void setAlpha(SongAdapter.ViewHolder holder, float alpha) {
if (holder.image != null) {
holder.image.setAlpha(alpha);
}
if (holder.title != null) {
holder.title.setAlpha(alpha);
}
if (holder.text != null) {
holder.text.setAlpha(alpha);
}
if (holder.imageText != null) {
holder.imageText.setAlpha(alpha);
}
if (holder.paletteColorContainer != null) {
holder.paletteColorContainer.setAlpha(alpha);
}
}
}

View file

@ -93,8 +93,7 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Song song = dataSet.get(position);
final int defaultBarColor = ColorUtil.resolveColor(activity, R.attr.default_bar_color);
setColors(defaultBarColor, holder);
setColors(ColorUtil.resolveColor(activity, R.attr.default_bar_color), holder);
boolean isChecked = isChecked(song);
holder.itemView.setActivated(isChecked);
@ -108,40 +107,9 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
if (holder.text != null) {
holder.text.setText(getSongText(song));
}
if (holder.image != null) {
ImageLoader.getInstance().displayImage(
getSongImageLoaderUri(song),
holder.image,
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.postProcessor(new BitmapProcessor() {
@Override
public Bitmap process(Bitmap bitmap) {
holder.paletteColor = ColorUtil.generateColor(activity, bitmap);
return bitmap;
}
})
.displayer(new FadeInBitmapDisplayer(FADE_IN_TIME, true, true, false) {
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
super.display(bitmap, imageAware, loadedFrom);
if (usePalette)
setColors(holder.paletteColor, holder);
}
})
.build(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
FadeInBitmapDisplayer.animate(view, FADE_IN_TIME);
if (usePalette)
setColors(defaultBarColor, holder);
}
}
);
}
loadAlbumCover(song, holder);
}
private void setColors(int color, ViewHolder holder) {
@ -156,6 +124,42 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
}
}
protected void loadAlbumCover(Song song, final ViewHolder holder) {
if (holder.image == null) return;
ImageLoader.getInstance().displayImage(
getSongImageLoaderUri(song),
holder.image,
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.postProcessor(new BitmapProcessor() {
@Override
public Bitmap process(Bitmap bitmap) {
holder.paletteColor = ColorUtil.generateColor(activity, bitmap);
return bitmap;
}
})
.displayer(new FadeInBitmapDisplayer(FADE_IN_TIME, true, true, false) {
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
super.display(bitmap, imageAware, loadedFrom);
if (usePalette)
setColors(holder.paletteColor, holder);
}
})
.build(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
FadeInBitmapDisplayer.animate(view, FADE_IN_TIME);
if (usePalette)
setColors(ColorUtil.resolveColor(activity, R.attr.default_bar_color), holder);
}
}
);
}
protected String getSongTitle(Song song) {
return song.title;
}
@ -254,8 +258,7 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
@Override
public boolean onLongClick(View view) {
toggleChecked(getAdapterPosition());
return true;
return toggleChecked(getAdapterPosition());
}
}
}

View file

@ -6,6 +6,8 @@ package com.kabouzeid.gramophone.interfaces;
public interface MusicServiceEventListener {
void onPlayingMetaChanged();
void onQueueChanged();
void onPlayStateChanged();
void onRepeatModeChanged();

View file

@ -628,6 +628,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
public void moveSong(int from, int to) {
if (from == to) return;
final int currentPosition = getPosition();
Song songToMove = playingQueue.remove(from);
playingQueue.add(to, songToMove);

View file

@ -46,6 +46,7 @@ public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements
filter.addAction(MusicService.SHUFFLE_MODE_CHANGED);
filter.addAction(MusicService.REPEAT_MODE_CHANGED);
filter.addAction(MusicService.META_CHANGED);
filter.addAction(MusicService.QUEUE_CHANGED);
filter.addAction(MusicService.MEDIA_STORE_CHANGED);
registerReceiver(musicStateReceiver, filter);
@ -93,6 +94,15 @@ public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements
}
}
@Override
public void onQueueChanged() {
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
if (listener != null) {
listener.onQueueChanged();
}
}
}
@Override
public void onPlayStateChanged() {
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
@ -146,6 +156,9 @@ public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements
case MusicService.META_CHANGED:
activity.onPlayingMetaChanged();
break;
case MusicService.QUEUE_CHANGED:
activity.onQueueChanged();
break;
case MusicService.PLAY_STATE_CHANGED:
activity.onPlayStateChanged();
break;

View file

@ -114,6 +114,11 @@ public abstract class AbsMainActivityRecyclerViewFragment<A extends RecyclerView
}
@Override
public void onQueueChanged() {
}
@Override
public void onPlayStateChanged() {

View file

@ -120,6 +120,11 @@ public class MiniPlayerFragment extends Fragment implements MusicServiceEventLis
miniPlayerTitle.setText(MusicPlayerRemote.getCurrentSong().title);
}
@Override
public void onQueueChanged() {
}
@Override
public void onPlayStateChanged() {
updatePlayPauseDrawableState(true);

View file

@ -121,6 +121,11 @@ public class PlaybackControlsFragment extends Fragment implements MusicServiceEv
public void onPlayingMetaChanged() {
}
@Override
public void onQueueChanged() {
}
@Override
public void onPlayStateChanged() {
updatePlayPauseDrawableState(true);
@ -229,8 +234,8 @@ public class PlaybackControlsFragment extends Fragment implements MusicServiceEv
lastPlaybackControlsColor));
break;
default:
shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_trending_flat_white_36dp,
lastPlaybackControlsColor));
shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp,
ColorUtil.getColorWithAlpha(0.5f, lastPlaybackControlsColor)));
break;
}
}
@ -256,8 +261,8 @@ public class PlaybackControlsFragment extends Fragment implements MusicServiceEv
lastPlaybackControlsColor));
break;
default:
repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_off_white_36dp,
lastPlaybackControlsColor));
repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp,
ColorUtil.getColorWithAlpha(0.5f, lastPlaybackControlsColor)));
break;
}
}

View file

@ -93,6 +93,11 @@ public class PlayerAlbumCoverFragment extends Fragment implements MusicServiceEv
loadAlbumCover();
}
@Override
public void onQueueChanged() {
}
@Override
public void onPlayStateChanged() {

View file

@ -32,10 +32,10 @@ import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.dialogs.SongDetailDialog;
import com.kabouzeid.gramophone.dialogs.SongShareDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener;
import com.kabouzeid.gramophone.interfaces.PaletteColorHolder;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.misc.DragSortRecycler;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity;
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
@ -75,9 +75,7 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
@Bind(R.id.player_queue_subheader)
TextView playerQueueSubheader;
@Bind(R.id.current_song)
View currentSong;
MediaEntryViewHolder mediaEntryViewHolder;
MediaEntryViewHolder currentSongViewHolder;
private int lastColor;
@ -89,6 +87,8 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
private LinearLayoutManager layoutManager;
private PlayingQueueAdapter playingQueueAdapter;
@Override
public void onAttach(Context context) {
super.onAttach(context);
@ -126,19 +126,23 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
setUpPlayerToolbar();
setUpSubFragments();
recyclerView.setAdapter(new PlayingQueueAdapter(
playingQueueAdapter = new PlayingQueueAdapter(
((AppCompatActivity) getActivity()),
SongLoader.getAllSongs(getActivity()),
MusicPlayerRemote.getPlayingQueue(),
R.layout.item_list,
false,
((CabHolder) getActivity())));
null);
recyclerView.setAdapter(playingQueueAdapter);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setChildSize((int) (getResources().getDisplayMetrics().density * 72));
recyclerView.setLayoutManager(layoutManager);
setUpDragSort();
//slidingUpPanelLayout.setParallaxOffset(Util.resolveDimensionPixelSize(activity, R.attr.actionBarSize) + getResources().getDimensionPixelSize(R.dimen.status_bar_padding));
slidingUpPanelLayout.setPanelSlideListener(this);
slidingUpPanelLayout.setAntiDragView(view.findViewById(R.id.draggable_area));
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
@ -150,15 +154,7 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
activity.addMusicServiceEventListener(this);
mediaEntryViewHolder = new MediaEntryViewHolder(currentSong) {
};
mediaEntryViewHolder.separator.setVisibility(View.VISIBLE);
mediaEntryViewHolder.shortSeparator.setVisibility(View.GONE);
mediaEntryViewHolder.title.setText("When I'm Gone");
mediaEntryViewHolder.text.setText("Eminem");
mediaEntryViewHolder.image.setScaleType(ImageView.ScaleType.CENTER);
mediaEntryViewHolder.image.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_volume_up_white_24dp, ColorUtil.resolveColor(activity, R.attr.icon_color)));
setUpCurrentSongView();
}
@Override
@ -171,6 +167,13 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
@Override
public void onPlayingMetaChanged() {
updatePlayerMenu();
updateCurrentSong();
updateQueue();
}
@Override
public void onQueueChanged() {
updateQueue();
}
@Override
@ -193,6 +196,20 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
}
private void updateQueue() {
playingQueueAdapter.swapDataSet(MusicPlayerRemote.getPlayingQueue(), MusicPlayerRemote.getPosition());
if (slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
resetToCurrentPosition();
}
}
@SuppressWarnings("ConstantConditions")
private void updateCurrentSong() {
Song song = MusicPlayerRemote.getCurrentSong();
currentSongViewHolder.title.setText(song.title);
currentSongViewHolder.text.setText(song.artistName);
}
private void setUpPanelAndAlbumCoverHeight() {
int topMargin = getResources().getDimensionPixelSize(R.dimen.status_bar_padding);
@ -225,6 +242,16 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
toolbar.setOnMenuItemClickListener(this);
}
@SuppressWarnings("ConstantConditions")
private void setUpCurrentSongView() {
currentSongViewHolder = new MediaEntryViewHolder(getView().findViewById(R.id.current_song));
currentSongViewHolder.separator.setVisibility(View.VISIBLE);
currentSongViewHolder.shortSeparator.setVisibility(View.GONE);
currentSongViewHolder.image.setScaleType(ImageView.ScaleType.CENTER);
currentSongViewHolder.image.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_volume_up_white_24dp, ColorUtil.resolveColor(activity, R.attr.icon_color)));
}
private void updatePlayerMenu() {
boolean isFavorite = MusicUtil.isFavorite(activity, MusicPlayerRemote.getCurrentSong());
Drawable favoriteIcon = Util.getTintedDrawable(activity, isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_outline_white_24dp, ViewUtil.getToolbarIconColor(activity, false));
@ -233,6 +260,23 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
.setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites));
}
private void setUpDragSort() {
DragSortRecycler dragSortRecycler = new DragSortRecycler();
dragSortRecycler.setViewHandleId(R.id.image_text);
dragSortRecycler.setOnItemMovedListener(new DragSortRecycler.OnItemMovedListener() {
@Override
public void onItemMoved(int from, int to) {
if (from == to) return;
MusicPlayerRemote.moveSong(from, to);
}
});
recyclerView.addItemDecoration(dragSortRecycler);
recyclerView.addOnItemTouchListener(dragSortRecycler);
recyclerView.addOnScrollListener(dragSortRecycler.getScrollListener());
recyclerView.setItemAnimator(null);
}
@Override
@ColorInt
public int getPaletteColor() {
@ -343,11 +387,12 @@ public class PlayerFragment extends Fragment implements MusicServiceEventListene
@Override
public void onPanelCollapsed(View view) {
if (layoutManager.findLastVisibleItemPosition() < 50) {
recyclerView.smoothScrollToPosition(0);
} else {
recyclerView.scrollToPosition(0);
}
resetToCurrentPosition();
}
private void resetToCurrentPosition() {
recyclerView.stopScroll();
layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0);
}
@Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

View file

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<com.sothree.slidinguppanel.SlidingUpPanelLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.sothree.slidinguppanel.SlidingUpPanelLayout
android:id="@+id/player_sliding_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="@+id/player_sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
@ -79,30 +80,47 @@
app:cardElevation="@dimen/card_elevation"
app:cardUseCompatPadding="false">
<LinearLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="wrap_content">
<include android:id="@+id/current_song" layout="@layout/item_list" />
<TextView
android:id="@+id/player_queue_subheader"
android:gravity="center_vertical"
android:text="Up next"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="?android:textColorSecondary"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:layout_width="match_parent"
android:layout_height="48dp" />
<android.support.v7.widget.RecyclerView
android:id="@+id/player_recycler_view"
android:layout_width="match_parent"
<!--This is necessary for the drag sorting to work at the top-->
<View
android:layout_alignTop="@+id/card_content"
android:layout_alignBottom="@+id/card_content"
android:id="@+id/draggable_area"
android:layout_width="72dp"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/card_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/current_song"
layout="@layout/item_list" />
<TextView
android:id="@+id/player_queue_subheader"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="@string/up_next"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="?android:textColorSecondary" />
<android.support.v7.widget.RecyclerView
android:id="@+id/player_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>

View file

@ -12,9 +12,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginLeft="-12dp"
android:layout_marginStart="-12dp"
android:src="@drawable/ic_equal_white_24dp"
android:layout_marginLeft="-8dp"
android:layout_marginStart="-8dp"
android:src="@drawable/ic_drag_vertical_white_24dp"
android:tint="?icon_color"
tools:ignore="ContentDescription" />

View file

@ -12,9 +12,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginLeft="-12dp"
android:layout_marginStart="-12dp"
android:src="@drawable/ic_equal_white_24dp"
android:layout_marginLeft="-8dp"
android:layout_marginStart="-8dp"
android:src="@drawable/ic_drag_vertical_white_24dp"
android:tint="?icon_color"
tools:ignore="ContentDescription" />

View file

@ -205,7 +205,5 @@
<string name="aleksandar_tesic_summary">For helping me with the design.</string>
<string name="website">Website</string>
<string name="loading_products">Loading products…</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="up_next">Up next</string>
</resources>