-Modified play queue action buttons on playlist and channel fragments.

-Added info item menu with custom title banner on long click.
-Enabled starting playlists and channels from middle.
-Enabled caching for play queue item thumbnails.
-Modified play queue to revert to first item on deleting last item.
This commit is contained in:
John Zhen Mo 2017-11-11 14:47:34 -08:00
parent cf147aa161
commit ce36f3ae3b
16 changed files with 464 additions and 125 deletions

View file

@ -63,6 +63,7 @@ import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.history.HistoryListener; import org.schabi.newpipe.history.HistoryListener;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
@ -460,6 +461,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
public void selected(StreamInfoItem selectedItem) { public void selected(StreamInfoItem selectedItem) {
selectAndLoadVideo(selectedItem.service_id, selectedItem.url, selectedItem.name); selectAndLoadVideo(selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
@Override
public void held(StreamInfoItem selectedItem) {
showStreamDialog(selectedItem);
}
}); });
videoTitleRoot.setOnClickListener(this); videoTitleRoot.setOnClickListener(this);
@ -477,6 +483,32 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
detailControlsPopup.setOnTouchListener(getOnControlsTouchListener()); detailControlsPopup.setOnTouchListener(getOnControlsTouchListener());
} }
private void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup)
};
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
break;
default:
break;
}
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
private View.OnTouchListener getOnControlsTouchListener() { private View.OnTouchListener getOnControlsTouchListener() {
return new View.OnTouchListener() { return new View.OnTouchListener() {
@Override @Override

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.fragments.list; package org.schabi.newpipe.fragments.list;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
@ -10,7 +11,6 @@ import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.widget.PopupMenu;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
@ -20,7 +20,9 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.StateSaver; import org.schabi.newpipe.util.StateSaver;
@ -140,6 +142,11 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(), useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name); selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
@Override
public void held(StreamInfoItem selectedItem) {
showStreamDialog(selectedItem);
}
}); });
infoListAdapter.setOnChannelSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<ChannelInfoItem>() { infoListAdapter.setOnChannelSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<ChannelInfoItem>() {
@ -150,6 +157,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(), useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name); selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
@Override
public void held(ChannelInfoItem selectedItem) {}
}); });
infoListAdapter.setOnPlaylistSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<PlaylistInfoItem>() { infoListAdapter.setOnPlaylistSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<PlaylistInfoItem>() {
@ -160,6 +170,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(), useAsFrontPage?getParentFragment().getFragmentManager():getFragmentManager(),
selectedItem.service_id, selectedItem.url, selectedItem.name); selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
@Override
public void held(PlaylistInfoItem selectedItem) {}
}); });
itemsList.clearOnScrollListeners(); itemsList.clearOnScrollListeners();
@ -177,6 +190,31 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
} }
} }
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup)
};
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
break;
default:
break;
}
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Menu // Menu
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.fragments.list.channel; package org.schabi.newpipe.fragments.list.channel;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
@ -20,6 +21,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -31,10 +33,13 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.fragments.subscription.SubscriptionService; import org.schabi.newpipe.fragments.subscription.SubscriptionService;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.ChannelPlayQueue; import org.schabi.newpipe.playlist.ChannelPlayQueue;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
@ -76,9 +81,9 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
private TextView headerSubscribersTextView; private TextView headerSubscribersTextView;
private Button headerSubscribeButton; private Button headerSubscribeButton;
private Button headerPlayAllButton; private LinearLayout headerPlayAllButton;
private Button headerPopupButton; private LinearLayout headerPopupButton;
private Button headerBackgroundButton; private LinearLayout headerBackgroundButton;
private MenuItem menuRssButton; private MenuItem menuRssButton;
@ -136,13 +141,52 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view); headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view);
headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button); headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button);
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_play_all_button); headerPlayAllButton = headerRootLayout.findViewById(R.id.channel_play_all_button);
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_play_popup_button); headerPopupButton = headerRootLayout.findViewById(R.id.channel_play_popup_button);
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_play_bg_button); headerBackgroundButton = headerRootLayout.findViewById(R.id.channel_play_bg_button);
return headerRootLayout; return headerRootLayout;
} }
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup),
context.getResources().getString(R.string.start_here_on_main),
context.getResources().getString(R.string.start_here_on_background),
context.getResources().getString(R.string.start_here_on_popup),
};
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
break;
case 3:
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index));
break;
default:
break;
}
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Menu // Menu
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -435,12 +479,16 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
} }
private PlayQueue getPlayQueue() { private PlayQueue getPlayQueue() {
return getPlayQueue(0);
}
private PlayQueue getPlayQueue(final int index) {
return new ChannelPlayQueue( return new ChannelPlayQueue(
currentInfo.service_id, currentInfo.service_id,
currentInfo.url, currentInfo.url,
currentInfo.next_streams_url, currentInfo.next_streams_url,
infoListAdapter.getItemsList(), infoListAdapter.getItemsList(),
0 index
); );
} }

View file

@ -1,5 +1,7 @@
package org.schabi.newpipe.fragments.list.playlist; package org.schabi.newpipe.fragments.list.playlist;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -12,8 +14,8 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -22,9 +24,12 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.playlist.PlaylistPlayQueue; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.playlist.PlayQueue; import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@ -47,9 +52,9 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private ImageView headerUploaderAvatar; private ImageView headerUploaderAvatar;
private TextView headerStreamCount; private TextView headerStreamCount;
private Button headerPlayAllButton; private LinearLayout headerPlayAllButton;
private Button headerPopupButton; private LinearLayout headerPopupButton;
private Button headerBackgroundButton; private LinearLayout headerBackgroundButton;
public static PlaylistFragment getInstance(int serviceId, String url, String name) { public static PlaylistFragment getInstance(int serviceId, String url, String name) {
PlaylistFragment instance = new PlaylistFragment(); PlaylistFragment instance = new PlaylistFragment();
@ -99,6 +104,45 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
inflater.inflate(R.menu.menu_playlist, menu); inflater.inflate(R.menu.menu_playlist, menu);
} }
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final String[] commands = new String[]{
context.getResources().getString(R.string.enqueue_on_background),
context.getResources().getString(R.string.enqueue_on_popup),
context.getResources().getString(R.string.start_here_on_main),
context.getResources().getString(R.string.start_here_on_background),
context.getResources().getString(R.string.start_here_on_popup),
};
final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0);
switch (i) {
case 0:
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
break;
case 3:
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index));
break;
default:
break;
}
}
};
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Load and handle // Load and handle
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -181,12 +225,16 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
} }
private PlayQueue getPlayQueue() { private PlayQueue getPlayQueue() {
return getPlayQueue(0);
}
private PlayQueue getPlayQueue(final int index) {
return new PlaylistPlayQueue( return new PlaylistPlayQueue(
currentInfo.service_id, currentInfo.service_id,
currentInfo.url, currentInfo.url,
currentInfo.next_streams_url, currentInfo.next_streams_url,
infoListAdapter.getItemsList(), infoListAdapter.getItemsList(),
0 index
); );
} }

View file

@ -132,6 +132,9 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name); NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name);
} }
@Override
public void held(ChannelInfoItem selectedItem) {}
}); });
headerRootLayout.setOnClickListener(new View.OnClickListener() { headerRootLayout.setOnClickListener(new View.OnClickListener() {

View file

@ -44,6 +44,7 @@ public class InfoItemBuilder {
public interface OnInfoItemSelectedListener<T extends InfoItem> { public interface OnInfoItemSelectedListener<T extends InfoItem> {
void selected(T selectedItem); void selected(T selectedItem);
void held(T selectedItem);
} }
private final Context context; private final Context context;

View file

@ -0,0 +1,39 @@
package org.schabi.newpipe.info_list;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
public class InfoItemDialog {
private final AlertDialog dialog;
public InfoItemDialog(@NonNull final Activity activity,
@NonNull final InfoItem item,
@NonNull final String[] commands,
@NonNull final DialogInterface.OnClickListener actions) {
final LayoutInflater inflater = activity.getLayoutInflater();
final View bannerView = inflater.inflate(R.layout.dialog_title, null);
bannerView.setSelected(true);
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
titleView.setText(item.name);
TextView typeView = bannerView.findViewById(R.id.itemTypeView);
typeView.setText(item.info_type.name());
dialog = new AlertDialog.Builder(activity)
.setCustomTitle(bannerView)
.setItems(commands, actions)
.create();
}
public void show() {
dialog.show();
}
}

View file

@ -67,6 +67,38 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
} }
} }
}); });
switch (item.stream_type) {
case AUDIO_STREAM:
case VIDEO_STREAM:
case FILE:
enableLongClick(item);
break;
case LIVE_STREAM:
case AUDIO_LIVE_STREAM:
case NONE:
default:
disableLongClick();
break;
}
}
private void enableLongClick(final StreamInfoItem item) {
itemView.setLongClickable(true);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (itemBuilder.getOnStreamSelectedListener() != null) {
itemBuilder.getOnStreamSelectedListener().held(item);
}
return true;
}
});
}
private void disableLongClick() {
itemView.setLongClickable(false);
itemView.setOnLongClickListener(null);
} }
/** /**

View file

@ -444,20 +444,22 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (player == null) return;
if (view.getId() == repeatButton.getId()) { if (view.getId() == repeatButton.getId()) {
if (player != null) player.onRepeatClicked(); player.onRepeatClicked();
} else if (view.getId() == backwardButton.getId()) { } else if (view.getId() == backwardButton.getId()) {
if (player != null) player.onPlayPrevious(); player.onPlayPrevious();
} else if (view.getId() == playPauseButton.getId()) { } else if (view.getId() == playPauseButton.getId()) {
if (player != null) player.onVideoPlayPause(); player.onVideoPlayPause();
} else if (view.getId() == forwardButton.getId()) { } else if (view.getId() == forwardButton.getId()) {
if (player != null) player.onPlayNext(); player.onPlayNext();
} else if (view.getId() == shuffleButton.getId()) { } else if (view.getId() == shuffleButton.getId()) {
if (player != null) player.onShuffleClicked(); player.onShuffleClicked();
} else if (view.getId() == playbackSpeedButton.getId()) { } else if (view.getId() == playbackSpeedButton.getId()) {
playbackSpeedPopupMenu.show(); playbackSpeedPopupMenu.show();

View file

@ -279,7 +279,7 @@ public abstract class PlayQueue implements Serializable {
queueIndex.set(currentIndex % (size - 1)); queueIndex.set(currentIndex % (size - 1));
} else if (currentIndex == removeIndex && currentIndex == size - 1){ } else if (currentIndex == removeIndex && currentIndex == size - 1){
queueIndex.set(removeIndex - 1); queueIndex.set(0);
} }
if (backup != null) { if (backup != null) {

View file

@ -107,6 +107,8 @@ public class PlayQueueItemBuilder {
.bitmapConfig(Bitmap.Config.RGB_565) // Users won't be able to see much anyways .bitmapConfig(Bitmap.Config.RGB_565) // Users won't be able to see much anyways
.preProcessor(bitmapProcessor) .preProcessor(bitmapProcessor)
.imageScaleType(ImageScaleType.EXACTLY) .imageScaleType(ImageScaleType.EXACTLY)
.cacheInMemory(true)
.cacheOnDisk(true)
.build(); .build();
} }
} }

View file

@ -83,60 +83,88 @@
tools:visibility="visible"/> tools:visibility="visible"/>
</RelativeLayout> </RelativeLayout>
<RelativeLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="25dp"
android:id="@+id/play_control" android:id="@+id/play_control"
android:layout_marginRight="2dp" android:layout_margin="@dimen/software_component_item_padding"
android:layout_marginEnd="2dp"
android:layout_below="@+id/channel_metadata"> android:layout_below="@+id/channel_metadata">
<Button <LinearLayout
android:id="@+id/playlist_play_bg_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:layout_gravity="center_vertical|right" android:gravity="center"
android:layout_marginRight="2dp" android:clickable="true"
android:layout_toLeftOf="@+id/playlist_play_all_button" android:focusable="true"
android:layout_toStartOf="@+id/playlist_play_all_button" android:background="?attr/selectableItemBackground"
android:text="@string/controls_background_title" android:id="@+id/channel_play_bg_button">
android:textSize="@dimen/channel_rss_title_size" <TextView
android:textColor="?attr/colorAccent" android:layout_width="wrap_content"
android:theme="@style/RedButton" android:layout_height="wrap_content"
android:drawableLeft="?attr/audio" android:gravity="center_vertical"
android:drawablePadding="4dp" android:text="@string/controls_background_title"
tools:ignore="RtlHardcoded" android:textSize="@dimen/channel_rss_title_size"
tools:visibility="visible" /> android:textColor="?attr/colorAccent"
android:drawablePadding="4dp"
android:drawableLeft="?attr/audio"
android:drawableStart="?attr/audio"/>
</LinearLayout>
<Button <View android:id="@+id/anchorLeft"
android:id="@+id/playlist_play_all_button" android:layout_width="1dp"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:paddingTop="3dp"
android:layout_gravity="center_vertical|right" android:paddingBottom="3dp"
android:layout_marginRight="2dp" android:clickable="false"
android:layout_toLeftOf="@+id/playlist_play_popup_button" android:background="?attr/colorAccent"/>
android:layout_toStartOf="@+id/playlist_play_popup_button"
android:text="@string/play_all"
android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"
android:theme="@style/RedButton"
tools:ignore="RtlHardcoded"
tools:visibility="visible"/>
<Button <LinearLayout
android:id="@+id/playlist_play_popup_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:layout_gravity="center_vertical|right" android:gravity="center"
android:layout_alignParentRight="true" android:clickable="true"
android:text="@string/controls_popup_title" android:focusable="true"
android:textSize="@dimen/channel_rss_title_size" android:background="?attr/selectableItemBackground"
android:textColor="?attr/colorAccent" android:id="@+id/channel_play_all_button">
android:theme="@style/RedButton" <TextView
android:drawableLeft="?attr/popup" android:layout_width="wrap_content"
android:drawablePadding="4dp" android:layout_height="wrap_content"
tools:ignore="RtlHardcoded" android:gravity="center_vertical"
tools:visibility="visible" /> android:text="@string/play_all"
</RelativeLayout> android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"/>
</LinearLayout>
<View android:id="@+id/anchorRight"
android:layout_width="1dp"
android:layout_height="match_parent"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:clickable="false"
android:background="?attr/colorAccent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground"
android:id="@+id/channel_play_popup_button">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="@string/controls_popup_title"
android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"
android:drawablePadding="4dp"
android:drawableLeft="?attr/popup"
android:drawableStart="?attr/popup"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/itemRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:padding="@dimen/video_item_search_padding">
<TextView
android:id="@+id/itemTitleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/video_item_search_title_text_size"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. "/>
<TextView
android:id="@+id/itemTypeView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/itemTitleView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_uploader_text_size"
tools:text="TYPE" />
</RelativeLayout>

View file

@ -79,8 +79,7 @@
android:layout_toLeftOf="@id/itemHandle" android:layout_toLeftOf="@id/itemHandle"
android:layout_toStartOf="@id/itemHandle" android:layout_toStartOf="@id/itemHandle"
android:ellipsize="end" android:ellipsize="end"
android:lines="1" android:singleLine="true"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceLarge" android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/video_item_search_title_text_size" android:textSize="@dimen/video_item_search_title_text_size"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. "/> tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. "/>
@ -94,7 +93,8 @@
android:layout_toEndOf="@id/itemThumbnailView" android:layout_toEndOf="@id/itemThumbnailView"
android:layout_toLeftOf="@id/itemHandle" android:layout_toLeftOf="@id/itemHandle"
android:layout_toStartOf="@id/itemHandle" android:layout_toStartOf="@id/itemHandle"
android:lines="1" android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_upload_date_text_size" android:textSize="@dimen/video_item_search_upload_date_text_size"
tools:text="Uploader"/> tools:text="Uploader"/>

View file

@ -6,8 +6,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/contrast_background_color" android:background="?attr/contrast_background_color">
android:paddingBottom="6dp">
<TextView <TextView
android:id="@+id/playlist_title_view" android:id="@+id/playlist_title_view"
@ -81,64 +80,90 @@
android:textSize="@dimen/playlist_detail_subtext_size" android:textSize="@dimen/playlist_detail_subtext_size"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:text="234 videos"/> tools:text="234 videos"/>
</RelativeLayout> </RelativeLayout>
<LinearLayout
<RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="25dp"
android:id="@+id/play_control" android:id="@+id/play_control"
android:paddingLeft="5dp" android:layout_margin="@dimen/software_component_item_padding"
android:paddingRight="5dp"
android:layout_below="@+id/playlist_meta"> android:layout_below="@+id/playlist_meta">
<Button <LinearLayout
android:id="@+id/playlist_play_bg_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:layout_gravity="center_vertical|right" android:gravity="center"
android:layout_marginRight="2dp" android:clickable="true"
android:layout_toLeftOf="@+id/playlist_play_all_button" android:focusable="true"
android:layout_toStartOf="@+id/playlist_play_all_button" android:background="?attr/selectableItemBackground"
android:text="@string/controls_background_title" android:id="@+id/playlist_play_bg_button">
android:textSize="@dimen/channel_rss_title_size" <TextView
android:textColor="?attr/colorAccent" android:layout_width="wrap_content"
android:theme="@style/RedButton" android:layout_height="wrap_content"
android:drawableLeft="?attr/audio" android:gravity="center_vertical"
android:drawablePadding="4dp" android:text="@string/controls_background_title"
tools:ignore="RtlHardcoded" android:textSize="@dimen/channel_rss_title_size"
tools:visibility="visible" /> android:textColor="?attr/colorAccent"
android:drawablePadding="4dp"
android:drawableLeft="?attr/audio"
android:drawableStart="?attr/audio"/>
</LinearLayout>
<Button <View android:id="@+id/anchorLeft"
android:id="@+id/playlist_play_all_button" android:layout_width="1dp"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:paddingTop="3dp"
android:layout_gravity="center_vertical|right" android:paddingBottom="3dp"
android:layout_marginRight="2dp" android:clickable="false"
android:layout_toLeftOf="@+id/playlist_play_popup_button" android:background="?attr/colorAccent"/>
android:layout_toStartOf="@+id/playlist_play_popup_button"
android:text="@string/play_all"
android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"
android:theme="@style/RedButton"
tools:ignore="RtlHardcoded"
tools:visibility="visible"/>
<Button <LinearLayout
android:id="@+id/playlist_play_popup_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:layout_gravity="center_vertical|right" android:gravity="center"
android:layout_alignParentRight="true" android:clickable="true"
android:text="@string/controls_popup_title" android:focusable="true"
android:textSize="@dimen/channel_rss_title_size" android:background="?attr/selectableItemBackground"
android:textColor="?attr/colorAccent" android:id="@+id/playlist_play_all_button">
android:theme="@style/RedButton" <TextView
android:drawableLeft="?attr/popup" android:layout_width="wrap_content"
android:drawablePadding="4dp" android:layout_height="wrap_content"
tools:ignore="RtlHardcoded" android:gravity="center_vertical"
tools:visibility="visible" /> android:text="@string/play_all"
</RelativeLayout> android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"/>
</LinearLayout>
<View android:id="@+id/anchorRight"
android:layout_width="1dp"
android:layout_height="match_parent"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:clickable="false"
android:background="?attr/colorAccent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground"
android:id="@+id/playlist_play_popup_button">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="@string/controls_popup_title"
android:textSize="@dimen/channel_rss_title_size"
android:textColor="?attr/colorAccent"
android:drawablePadding="4dp"
android:drawableLeft="?attr/popup"
android:drawableStart="?attr/popup"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -310,4 +310,9 @@
<string name="play_queue_stream_detail">Details</string> <string name="play_queue_stream_detail">Details</string>
<string name="play_queue_audio_settings">Audio Settings</string> <string name="play_queue_audio_settings">Audio Settings</string>
<string name="hold_to_append">Hold To Enqueue</string> <string name="hold_to_append">Hold To Enqueue</string>
<string name="enqueue_on_background">Enqueue on Background</string>
<string name="enqueue_on_popup">Enqueue on Popup</string>
<string name="start_here_on_main">Start Playing Here</string>
<string name="start_here_on_background">Start Here on Background</string>
<string name="start_here_on_popup">Start Here on Popup</string>
</resources> </resources>