Showcase app: Added media row actions to the music fragment
am: f797f525ce
* commit 'f797f525ce3b5ce0338a18e64ece25e7bd5d8b1f':
Showcase app: Added media row actions to the music fragment
Change-Id: I975255da9e985ae65951cf02502bbd9d0354defe
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/app_banner_sample_app"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:largeHeap="true"
|
||||
android:theme="@style/Theme.Example.LeanbackLauncher">
|
||||
<activity
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.app.PlaybackControlGlue;
|
||||
import android.support.v17.leanback.app.PlaybackOverlayFragment;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.R;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
|
||||
@@ -66,7 +67,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
private PlaybackControlsRow mControlsRow;
|
||||
private Runnable mRunnable;
|
||||
private Handler mHandler = new Handler();
|
||||
private boolean mPaused = false;
|
||||
private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
|
||||
private OnMediaFileFinishedPlayingListener mMediaFileFinishedPlayingListener;
|
||||
private Action mSelectedAction; // the action which is currently selected by the user
|
||||
@@ -87,10 +87,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
|
||||
mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
|
||||
|
||||
// Setup controls and notify UI about change.
|
||||
setFadingEnabled(false);
|
||||
onStateChanged();
|
||||
|
||||
// Register selected listener such that we know what action the user currently has focused.
|
||||
fragment.setOnItemViewSelectedListener(this);
|
||||
}
|
||||
@@ -100,8 +96,8 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
* not required to call this method before playing the first file. However you have to call it
|
||||
* before playing a second one.
|
||||
*/
|
||||
public void reset() {
|
||||
mPaused = mInitialized = false;
|
||||
void reset() {
|
||||
mInitialized = false;
|
||||
mPlayer.reset();
|
||||
}
|
||||
|
||||
@@ -137,8 +133,8 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
*/
|
||||
public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
|
||||
// TODO: hahnr@ move into resources
|
||||
presenter.setProgressColor(Color.parseColor("#feab91"));
|
||||
presenter.setBackgroundColor(Color.parseColor("#db2a0f"));
|
||||
presenter.setProgressColor(getContext().getColor(R.color.player_progress_color));
|
||||
presenter.setBackgroundColor(getContext().getColor(R.color.player_background_color));
|
||||
}
|
||||
|
||||
@Override public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
|
||||
@@ -260,47 +256,12 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
}
|
||||
|
||||
@Override protected void startPlayback(int speed) throws IllegalStateException {
|
||||
if (mPaused) {
|
||||
mPlayer.start();
|
||||
} else if (!isMediaPlaying()) {
|
||||
reset();
|
||||
try {
|
||||
if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
|
||||
else mPlayer.setDataSource(mMediaSourcePath);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override public void onPrepared(MediaPlayer mp) {
|
||||
mInitialized = true;
|
||||
mPaused = false;
|
||||
mPlayer.start();
|
||||
onMetadataChanged();
|
||||
onStateChanged();
|
||||
updateProgress();
|
||||
}
|
||||
});
|
||||
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override public void onCompletion(MediaPlayer mp) {
|
||||
if (mInitialized && mMediaFileFinishedPlayingListener != null)
|
||||
mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
|
||||
}
|
||||
});
|
||||
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
|
||||
@Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
|
||||
}
|
||||
});
|
||||
mPlayer.prepareAsync();
|
||||
onStateChanged();
|
||||
}
|
||||
mPlayer.start();
|
||||
}
|
||||
|
||||
@Override protected void pausePlayback() {
|
||||
if (mPlayer.isPlaying()) {
|
||||
mPlayer.pause();
|
||||
mPaused = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +287,40 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
* @see MediaPlayer#setDataSource(Context, Uri)
|
||||
*/
|
||||
public void setMediaSource(Uri uri) {
|
||||
if (mMediaSourceUri != null && mMediaSourceUri.equals(uri)) {
|
||||
return;
|
||||
}
|
||||
mMediaSourceUri = uri;
|
||||
reset();
|
||||
try {
|
||||
if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
|
||||
else mPlayer.setDataSource(mMediaSourcePath);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override public void onPrepared(MediaPlayer mp) {
|
||||
mInitialized = true;
|
||||
mPlayer.start();
|
||||
onMetadataChanged();
|
||||
onStateChanged();
|
||||
updateProgress();
|
||||
}
|
||||
});
|
||||
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override public void onCompletion(MediaPlayer mp) {
|
||||
if (mInitialized && mMediaFileFinishedPlayingListener != null)
|
||||
mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
|
||||
}
|
||||
});
|
||||
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
|
||||
@Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
|
||||
}
|
||||
});
|
||||
mPlayer.prepareAsync();
|
||||
onStateChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,7 +411,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
private String mArtist;
|
||||
private Drawable mCover;
|
||||
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
@@ -441,6 +434,7 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
|
||||
public void setCover(Drawable cover) {
|
||||
this.mCover = cover;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,25 +14,19 @@
|
||||
|
||||
package android.support.v17.leanback.supportleanbackshowcase.app.media;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v17.leanback.app.PlaybackOverlayFragment;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.utils.Constants;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.app.media.MediaPlayerGlue;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.R;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.app.media.TrackListHeader;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.models.Song;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.models.SongList;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ClassPresenterSelector;
|
||||
import android.support.v17.leanback.widget.OnItemViewClickedListener;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.support.v17.leanback.widget.*;
|
||||
import android.support.v17.leanback.widget.AbstractMediaItemPresenter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
@@ -43,10 +37,12 @@ import java.util.List;
|
||||
* This example shows how to play music files and build a simple track list.
|
||||
*/
|
||||
public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment implements
|
||||
OnItemViewClickedListener, Song.OnSongRowClickListener,
|
||||
BaseOnItemViewClickedListener, BaseOnItemViewSelectedListener,
|
||||
MediaPlayerGlue.OnMediaFileFinishedPlayingListener {
|
||||
|
||||
private static final String TAG = "MusicConsumptionExampleFragment";
|
||||
private static final int PLAYLIST_ACTION_ID = 0;
|
||||
private static final int FAVORITE_ACTION_ID = 1;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private MediaPlayerGlue mGlue;
|
||||
private int mCurrentSongIndex = 0;
|
||||
@@ -69,7 +65,38 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
|
||||
|
||||
String json = Utils.inputStreamToString(
|
||||
getResources().openRawResource(R.raw.music_consumption_example));
|
||||
|
||||
|
||||
mSongList = new Gson().fromJson(json, SongList.class).getSongs();
|
||||
|
||||
Resources res = getActivity().getResources();
|
||||
|
||||
// For each song add a playlist and favorite actions.
|
||||
for(Song song : mSongList) {
|
||||
MultiActionsProvider.MultiAction[] mediaRowActions = new
|
||||
MultiActionsProvider.MultiAction[2];
|
||||
MultiActionsProvider.MultiAction playlistAction = new
|
||||
MultiActionsProvider.MultiAction(PLAYLIST_ACTION_ID);
|
||||
Drawable[] playlistActionDrawables = new Drawable[] {
|
||||
res.getDrawable(R.drawable.ic_playlist_add_white_24dp,
|
||||
getActivity().getTheme()),
|
||||
res.getDrawable(R.drawable.ic_playlist_add_filled_24dp,
|
||||
getActivity().getTheme())};
|
||||
playlistAction.setDrawables(playlistActionDrawables);
|
||||
mediaRowActions[0] = playlistAction;
|
||||
|
||||
MultiActionsProvider.MultiAction favoriteAction = new
|
||||
MultiActionsProvider.MultiAction(FAVORITE_ACTION_ID);
|
||||
Drawable[] favoriteActionDrawables = new Drawable[] {
|
||||
res.getDrawable(R.drawable.ic_favorite_border_white_24dp,
|
||||
getActivity().getTheme()),
|
||||
res.getDrawable(R.drawable.ic_favorite_filled_24dp,
|
||||
getActivity().getTheme())};
|
||||
favoriteAction.setDrawables(favoriteActionDrawables);
|
||||
mediaRowActions[1] = favoriteAction;
|
||||
song.setMediaRowActions(mediaRowActions);
|
||||
}
|
||||
|
||||
Song song = mSongList.get(mCurrentSongIndex);
|
||||
MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData();
|
||||
metaData.setArtist(song.getDescription());
|
||||
@@ -79,7 +106,6 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
|
||||
mGlue.setMetaData(metaData);
|
||||
mGlue.setMediaSource(uri);
|
||||
|
||||
setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
|
||||
addPlaybackControlsRow();
|
||||
}
|
||||
|
||||
@@ -94,48 +120,175 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
|
||||
mGlue.reset();
|
||||
}
|
||||
|
||||
static class SongPresenter extends AbstractMediaItemPresenter {
|
||||
|
||||
SongPresenter() {
|
||||
super();
|
||||
}
|
||||
|
||||
SongPresenter(Context context, int themeResId) {
|
||||
super(themeResId);
|
||||
setHasMediaRowSeparator(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindMediaDetails(ViewHolder vh, Object item) {
|
||||
|
||||
int favoriteTextColor = vh.view.getContext().getResources().getColor(
|
||||
R.color.song_row_favorite_color);
|
||||
Song song = (Song) item;
|
||||
vh.getMediaItemNumberView().setText("" + song.getNumber());
|
||||
|
||||
String songTitle = song.getTitle() + " / " + song.getDescription();
|
||||
vh.getMediaItemNameView().setText(songTitle);
|
||||
|
||||
vh.getMediaItemDurationView().setText("" + song.getDuration());
|
||||
|
||||
if (song.isFavorite()) {
|
||||
vh.getMediaItemNumberView().setTextColor(favoriteTextColor);
|
||||
vh.getMediaItemNameView().setTextColor(favoriteTextColor);
|
||||
vh.getMediaItemDurationView().setTextColor(favoriteTextColor);
|
||||
} else {
|
||||
vh.getMediaItemNumberView().setTextAppearance(
|
||||
R.style.TextAppearance_Leanback_PlaybackMediaItemNumber);
|
||||
vh.getMediaItemNameView().setTextAppearance(
|
||||
R.style.TextAppearance_Leanback_PlaybackMediaItemName);
|
||||
vh.getMediaItemDurationView().setTextAppearance(
|
||||
R.style.TextAppearance_Leanback_PlaybackMediaItemDuration);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static class SongPresenterSelector extends PresenterSelector {
|
||||
Presenter mRegularPresenter;
|
||||
Presenter mFavoritePresenter;
|
||||
|
||||
/**
|
||||
* Adds a presenter to be used for the given class.
|
||||
*/
|
||||
public SongPresenterSelector setSongPresenterRegular(Presenter presenter) {
|
||||
mRegularPresenter = presenter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a presenter to be used for the given class.
|
||||
*/
|
||||
public SongPresenterSelector setSongPresenterFavorite(Presenter presenter) {
|
||||
mFavoritePresenter = presenter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presenter[] getPresenters() {
|
||||
return new Presenter[]{mRegularPresenter, mFavoritePresenter};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presenter getPresenter(Object item) {
|
||||
return ( (Song) item).isFavorite() ? mFavoritePresenter : mRegularPresenter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TrackListHeaderPresenter extends AbstractMediaListHeaderPresenter {
|
||||
|
||||
TrackListHeaderPresenter() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindMediaListHeaderViewHolder(ViewHolder vh, Object item) {
|
||||
vh.getHeaderView().setText("Tracklist");
|
||||
}
|
||||
};
|
||||
|
||||
private void addPlaybackControlsRow() {
|
||||
final PlaybackControlsRowPresenter controlsPresenter = mGlue
|
||||
.createControlsRowAndPresenter();
|
||||
ClassPresenterSelector selector = new ClassPresenterSelector();
|
||||
Song.Presenter songPresenter = new Song.Presenter(getActivity());
|
||||
songPresenter.setOnClickListener(this);
|
||||
selector.addClassPresenter(Song.class, songPresenter);
|
||||
selector.addClassPresenter(TrackListHeader.class,
|
||||
new TrackListHeader.Presenter(getActivity()));
|
||||
selector.addClassPresenter(PlaybackControlsRow.class, controlsPresenter);
|
||||
mRowsAdapter = new ArrayObjectAdapter(selector);
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ClassPresenterSelector()
|
||||
.addClassPresenterSelector(Song.class, new SongPresenterSelector()
|
||||
.setSongPresenterRegular(new SongPresenter(getActivity(),
|
||||
R.style.Theme_Example_LeanbackMusic_RegularSongNumbers))
|
||||
.setSongPresenterFavorite(new SongPresenter(getActivity(),
|
||||
R.style.Theme_Example_LeanbackMusic_FavoriteSongNumbers)))
|
||||
.addClassPresenter(TrackListHeader.class, new TrackListHeaderPresenter())
|
||||
.addClassPresenter(PlaybackControlsRow.class,
|
||||
mGlue.createControlsRowAndPresenter()));
|
||||
mRowsAdapter.add(mGlue.getControlsRow());
|
||||
mRowsAdapter.add(new TrackListHeader());
|
||||
mRowsAdapter.addAll(2, mSongList);
|
||||
setAdapter(mRowsAdapter);
|
||||
setOnItemViewClickedListener(this);
|
||||
setOnItemViewSelectedListener(this);
|
||||
}
|
||||
|
||||
public MusicConsumptionExampleFragment() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
if (!(item instanceof Action)) return;
|
||||
mGlue.onActionClicked((Action) item);
|
||||
RowPresenter.ViewHolder rowViewHolder, Object row) {
|
||||
|
||||
if (item instanceof Action) {
|
||||
// if the clicked item is a primary or secondary action in the playback controller
|
||||
mGlue.onActionClicked((Action) item);
|
||||
} else if (row instanceof Song) {
|
||||
// if a media item row is clicked
|
||||
Song clickedSong = (Song) row;
|
||||
AbstractMediaItemPresenter.ViewHolder songRowVh =
|
||||
(AbstractMediaItemPresenter.ViewHolder) rowViewHolder;
|
||||
|
||||
// if an action within a media item row is clicked
|
||||
if (item instanceof MultiActionsProvider.MultiAction) {
|
||||
if ( ((MultiActionsProvider.MultiAction) item).getId() == FAVORITE_ACTION_ID) {
|
||||
MultiActionsProvider.MultiAction favoriteAction =
|
||||
(MultiActionsProvider.MultiAction) item;
|
||||
MultiActionsProvider.MultiAction playlistAction =
|
||||
songRowVh.getMediaItemRowActions()[0];
|
||||
favoriteAction.incrementIndex();
|
||||
playlistAction.incrementIndex();;
|
||||
|
||||
clickedSong.setFavorite(!clickedSong.isFavorite());
|
||||
songRowVh.notifyDetailsChanged();
|
||||
songRowVh.notifyActionChanged(playlistAction);
|
||||
songRowVh.notifyActionChanged(favoriteAction);
|
||||
}
|
||||
} else if (item == null){
|
||||
// if a media item details is clicked, start playing that media item
|
||||
onSongDetailsClicked(clickedSong);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Object row) {
|
||||
}
|
||||
|
||||
|
||||
@Override public void onSongRowClicked(Song song) {
|
||||
mCurrentSongIndex = mSongList.indexOf(song);
|
||||
public void onSongDetailsClicked(Song song) {
|
||||
int nextSongIndex = mSongList.indexOf(song);
|
||||
mCurrentSongIndex = nextSongIndex;
|
||||
startPlayback();
|
||||
}
|
||||
|
||||
|
||||
@Override public void onMediaFileFinishedPlaying(MediaPlayerGlue.MetaData song) {
|
||||
if (mGlue.repeatOne()) {
|
||||
startPlayback();
|
||||
return;
|
||||
}
|
||||
if (mGlue.useShuffle()) {
|
||||
} else if (mGlue.useShuffle()) {
|
||||
mCurrentSongIndex = (int) (Math.random() * mSongList.size());
|
||||
} else mCurrentSongIndex++;
|
||||
if (mCurrentSongIndex >= mSongList.size()) {
|
||||
mCurrentSongIndex = 0;
|
||||
if (!mGlue.repeatAll()) return;
|
||||
} else {
|
||||
mCurrentSongIndex++;
|
||||
if (mCurrentSongIndex >= mSongList.size()) {
|
||||
mCurrentSongIndex = 0;
|
||||
if (!mGlue.repeatAll()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
startPlayback();
|
||||
}
|
||||
|
||||
@@ -15,36 +15,7 @@
|
||||
|
||||
package android.support.v17.leanback.supportleanbackshowcase.app.media;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.R;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class TrackListHeader extends Row {
|
||||
|
||||
public static class Presenter extends RowPresenter {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public Presenter(Context context) {
|
||||
mContext = context;
|
||||
setHeaderPresenter(null);
|
||||
}
|
||||
|
||||
@Override public boolean isUsingDefaultSelectEffect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
|
||||
View view = LayoutInflater.from(mContext).inflate(R.layout.row_track_list_header, parent, false);
|
||||
view.setFocusable(false);
|
||||
view.setFocusableInTouchMode(false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,17 +16,22 @@
|
||||
package android.support.v17.leanback.supportleanbackshowcase.models;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v17.leanback.supportleanbackshowcase.R;
|
||||
import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
|
||||
import android.support.v17.leanback.widget.MultiActionsProvider;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Song extends Row {
|
||||
public class Song implements MultiActionsProvider {
|
||||
|
||||
@SerializedName("title") private String mTitle = "";
|
||||
@SerializedName("description") private String mDescription = "";
|
||||
@@ -35,12 +40,27 @@ public class Song extends Row {
|
||||
@SerializedName("file") private String mFile = null;
|
||||
@SerializedName("duration") private String mDuration = null;
|
||||
@SerializedName("number") private int mNumber = 0;
|
||||
@SerializedName("favorite") private boolean mFavorite = false;
|
||||
|
||||
private MultiAction[] mMediaRowActions;
|
||||
|
||||
|
||||
public void setMediaRowActions(MultiAction[] mediaRowActions) {
|
||||
mMediaRowActions = mediaRowActions;
|
||||
}
|
||||
|
||||
public MultiAction[] getMediaRowActions() {
|
||||
return mMediaRowActions;
|
||||
}
|
||||
|
||||
public String getDuration() {
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
public void setDuration(String duration) {
|
||||
mDuration = duration;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return mNumber;
|
||||
}
|
||||
@@ -53,10 +73,26 @@ public class Song extends Row {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
mDescription = description;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
public boolean isFavorite() {
|
||||
return mFavorite;
|
||||
}
|
||||
|
||||
public void setFavorite(boolean favorite) {
|
||||
mFavorite = favorite;
|
||||
}
|
||||
|
||||
public int getFileResource(Context context) {
|
||||
return context.getResources()
|
||||
.getIdentifier(mFile, "raw", context.getPackageName());
|
||||
@@ -67,50 +103,9 @@ public class Song extends Row {
|
||||
.getIdentifier(mImage, "drawable", context.getPackageName());
|
||||
}
|
||||
|
||||
public interface OnSongRowClickListener {
|
||||
|
||||
void onSongRowClicked(Song song);
|
||||
|
||||
@Override
|
||||
public MultiAction[] getActions() {
|
||||
return mMediaRowActions;
|
||||
}
|
||||
|
||||
public static class Presenter extends RowPresenter implements View.OnClickListener {
|
||||
|
||||
private final Context mContext;
|
||||
private OnSongRowClickListener mClickListener;
|
||||
|
||||
|
||||
public Presenter(Context context) {
|
||||
mContext = context;
|
||||
setHeaderPresenter(null);
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnSongRowClickListener listener) {
|
||||
mClickListener = listener;
|
||||
}
|
||||
|
||||
@Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
|
||||
View view = LayoutInflater.from(mContext).inflate(R.layout.row_song, parent, false);
|
||||
view.findViewById(R.id.rowContainer).setOnClickListener(this);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override public boolean isUsingDefaultSelectEffect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override protected void onBindRowViewHolder(ViewHolder vh, Object item) {
|
||||
super.onBindRowViewHolder(vh, item);
|
||||
Song song = (Song) item;
|
||||
((TextView) vh.view.findViewById(R.id.trackNumber)).setText("" + song.getNumber());
|
||||
((TextView) vh.view.findViewById(R.id.trackDuration)).setText(song.getDuration());
|
||||
String text = song.getTitle() + " / " + song.getDescription();
|
||||
((TextView) vh.view.findViewById(R.id.trackName)).setText(text);
|
||||
vh.view.findViewById(R.id.rowContainer).setTag(item);
|
||||
}
|
||||
|
||||
@Override public void onClick(View v) {
|
||||
if (mClickListener == null) return;
|
||||
mClickListener.onSongRowClicked((Song) v.getTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"
|
||||
android:fillColor="@color/song_row_favorite_color"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM18,14v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2,16h8v-2L2,14v2z"
|
||||
android:fillColor="@color/song_row_favorite_color"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM18,14v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2,16h8v-2L2,14v2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:lb="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="@dimen/lb_playback_controls_margin_end"
|
||||
android:paddingStart="@dimen/lb_playback_controls_margin_start"
|
||||
lb:rowHeight="wrap_content">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rowContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/song_row_background"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trackNumber"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:fontFamily="sans-serif-regular"
|
||||
android:gravity="center_vertical"
|
||||
android:text="1"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trackName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toEndOf="@+id/trackNumber"
|
||||
android:layout_toLeftOf="@+id/trackDuration"
|
||||
android:fontFamily="sans-serif-regular"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:text="A Song!!11"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trackDuration"
|
||||
android:layout_width="66dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginRight="32dp"
|
||||
android:fontFamily="sans-serif-regular"
|
||||
android:gravity="center_vertical|right"
|
||||
android:text="1:13:54"
|
||||
android:textColor="#80FFFFFF"
|
||||
android:textSize="18sp"/>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:lb="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingEnd="@dimen/lb_playback_controls_margin_end"
|
||||
android:paddingStart="@dimen/lb_playback_controls_margin_start"
|
||||
lb:rowHeight="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="#263238"
|
||||
android:fontFamily="sans-serif-regular"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="32dp"
|
||||
android:text="Tracks"
|
||||
android:textColor="#80EEEEEE"
|
||||
android:textSize="18sp"/>
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
@@ -31,6 +31,7 @@
|
||||
<color name="default_card_footer_background_color">#37474F</color>
|
||||
<color name="selected_card_footer_background_color">#F0F</color>
|
||||
|
||||
<color name="lb_default_brand_color">#FF455A64</color>
|
||||
<color name="card_primary_text">#EEEEEE</color>
|
||||
<color name="card_secondary_text">#99EEEEEE</color>
|
||||
|
||||
@@ -41,10 +42,15 @@
|
||||
<color name="detail_view_actionbar_background">#04549D</color>
|
||||
<color name="detail_view_background">#0374BF</color>
|
||||
<color name="detail_view_related_background">#022A4E</color>
|
||||
<color name="song_row_favorite_color">#FF6E40</color>
|
||||
|
||||
<color name="app_guidedstep_actions_background">#C03800</color>
|
||||
<color name="app_guidedstep_subactions_background">#C03800</color>
|
||||
<color name="app_guidedstep_dialog_actions_background">#263238</color>
|
||||
<color name="settings_card_background">#0277BD</color>
|
||||
<color name="settings_card_background_focussed">#01579B</color>
|
||||
|
||||
<color name="player_progress_color">#feab91</color>
|
||||
<color name="player_background_color">#db2a0f</color>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<string name="wizard_example_watch_sd">Watch in standard definition on the web and supported devices</string>
|
||||
<string name="wizard_example_rental_period">Rental period: start within 30 days,\nfinish within 24 hours</string>
|
||||
<string name="wizard_example_input_card">Enter credit card number</string>
|
||||
<string name="wizard_example_expiration_date">Exp. date</string>
|
||||
<string name="wizard_example_expiration_date">Exp Date</string>
|
||||
<string name="wizard_example_payment_method">Payment Method</string>
|
||||
<string name="wizard_example_toast_payment_method_clicked">\'Payment Method\' clicked.</string>
|
||||
<string name="wizard_example_rent">Rent</string>
|
||||
|
||||
@@ -44,19 +44,18 @@
|
||||
</style>
|
||||
|
||||
|
||||
<style name="MovieCardSimpleStyle" parent="Widget.Leanback.ImageCardViewStyle">
|
||||
<style name="MovieCardTitleOnlyStyle" parent="Widget.Leanback.ImageCardViewStyle">
|
||||
<item name="lbImageCardViewType">Title</item>
|
||||
<item name="cardBackground">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Theme corresponding to the MovieCardSimpleStyle -->
|
||||
<style name="MovieCardSimpleTheme" parent="Theme.Leanback">
|
||||
<item name="imageCardViewStyle"> @style/MovieCardSimpleStyle </item>
|
||||
<item name="imageCardViewStyle"> @style/MovieCardTitleOnlyStyle </item>
|
||||
<item name="imageCardViewImageStyle">@style/MovieCardImageStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="MovieCardCompleteStyle" parent="MovieCardSimpleStyle">
|
||||
|
||||
<style name="MovieCardCompleteStyle" parent="MovieCardTitleOnlyStyle">
|
||||
<item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
|
||||
</style>
|
||||
|
||||
@@ -147,7 +146,7 @@
|
||||
</style>
|
||||
|
||||
<style name="GameCardStyle" parent="DefaultCardStyle">
|
||||
<item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
|
||||
<item name="lbImageCardViewType">Title|Content|IconOnRight</item>
|
||||
</style>
|
||||
|
||||
<!-- Theme corresponding to the GameCardStyle -->
|
||||
@@ -218,4 +217,55 @@
|
||||
<item name="imageCardViewInfoAreaStyle">@style/IconCardInfoAreaStyle</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="MediaListHeaderStyle" parent="Widget.Leanback.PlaybackMediaListHeaderStyle">
|
||||
<item name="android:background">#282248</item>
|
||||
</style>
|
||||
|
||||
<style name="SharedMediaItemRowStyle" parent="Widget.Leanback.PlaybackMediaItemRowStyle">
|
||||
<item name="android:background">#282248</item>
|
||||
</style>
|
||||
|
||||
<style name="RegularMediaItemTextStyle" parent="TextAppearance.Leanback.PlaybackMediaItemNumber">
|
||||
<item name="android:textColor">#FF6255</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:fontFamily">sans-serif-light</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="RegularMediaItemNumberStyle" parent="Widget.Leanback.PlaybackMediaItemNumberStyle">
|
||||
<item name="android:visibility">visible</item>
|
||||
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
|
||||
</style>
|
||||
|
||||
<style name="RegularMediaItemNameStyle" parent="Widget.Leanback.PlaybackMediaItemNameStyle">
|
||||
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
|
||||
</style>
|
||||
|
||||
<style name="RegularMediaItemDurationStyle" parent="Widget.Leanback.PlaybackMediaItemDurationStyle">
|
||||
<item name="android:visibility">visible</item>
|
||||
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
|
||||
</style>
|
||||
|
||||
|
||||
<style name="FavoriteMediaItemTextStyle" parent="TextAppearance.Leanback.PlaybackMediaItemNumber">
|
||||
<item name="android:textColor">#FF6E40</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="FavoriteMediaItemNumberStyle" parent="Widget.Leanback.PlaybackMediaItemNumberStyle">
|
||||
<item name="android:visibility">visible</item>
|
||||
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="FavoriteMediaItemNameStyle" parent="Widget.Leanback.PlaybackMediaItemNameStyle">
|
||||
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="FavoriteMediaItemDurationStyle" parent="Widget.Leanback.PlaybackMediaItemDurationStyle">
|
||||
<item name="android:visibility">visible</item>
|
||||
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -73,4 +73,22 @@
|
||||
<item name="android:windowBackground">@drawable/background_sax</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Example.LeanbackMusic.RegularSongNumbers">
|
||||
<!--<item name="playbackMediaItemRowStyle">@style/SharedMediaItemRowStyle</item>-->
|
||||
<item name="playbackMediaItemNumberStyle">@style/RegularMediaItemNumberStyle</item>
|
||||
<item name="playbackMediaItemNameStyle">@style/RegularMediaItemNameStyle</item>
|
||||
<item name="playbackMediaItemDurationStyle">@style/RegularMediaItemDurationStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Example.LeanbackMusic.FavoriteSongNumbers">
|
||||
<!--<item name="playbackMediaItemRowStyle">@style/SharedMediaItemRowStyle</item>-->
|
||||
<item name="playbackMediaItemNumberStyle">@style/FavoriteMediaItemNumberStyle</item>
|
||||
<item name="playbackMediaItemNameStyle">@style/FavoriteMediaItemNameStyle</item>
|
||||
<item name="playbackMediaItemDurationStyle">@style/FavoriteMediaItemDurationStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Example.LeanbackMusic.TrackListHeader">
|
||||
<item name="playbackMediaListHeaderStyle">@style/MediaListHeaderStyle</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user