NewPipe/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java

541 lines
22 KiB
Java
Raw Normal View History

package org.schabi.newpipe.fragments.list.channel;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.viewbinding.ViewBinding;
2020-10-31 21:55:45 +01:00
import com.jakewharton.rxbinding4.view.RxView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.databinding.ChannelHeaderBinding;
2020-11-03 06:26:29 +01:00
import org.schabi.newpipe.databinding.FragmentChannelBinding;
import org.schabi.newpipe.databinding.PlaylistControlBinding;
import org.schabi.newpipe.error.ErrorActivity;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
Add play next to long press menu & refactor enqueue methods (#6872) * added mvp play next button in long press menu; new intent handling, new long press dialog entry, new dialog functions, new strings * changed line length for checkstyle pass * cleaned comments, moved strings * Update app/src/main/res/values/strings.xml to make long press entry more descriptive Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> * Update app/src/main/res/values/strings.xml Co-authored-by: Stypox <stypox@pm.me> * replace redundant nextOnVideoPlayer methods Co-authored-by: Stypox <stypox@pm.me> * add enqueueNextOnPlayer and enqueueOnPlayer without selectOnAppend and RESUME_PLAYBACK/ deprecate enqueueNextOn*Player and enqueueOn*Player methods add getPlayerIntent, getPlayerEnqueueIntent and getPlayerEnqueueNextIntent without selectOnAppend and RESUME_PLAYBACK/ deprecate those with add section comments * removed deprecated methods removed redundant methods * removed deprecated methods removed redundant methods * replaced APPEND_ONLY, removed SELECT_ON_APPEND / replaced remaining enqueueOn*Player methods * now works with playlists * renamed dialog entry * checking for >1 items in the queue using the PlayerHolder * making enqueue*OnPlayer safe to call when no video is playing (defaulting to audio) * corrected strings * improve getQueueSize in PlayerHolder * long press to enqueue only if queue isnt empty * add Whitespace Co-authored-by: Stypox <stypox@pm.me> * clarify comments / add spaces * PlayerType as parameter of the enqueueOnPlayer method add Helper method * using the helper function everywhere (except for the background and popup long-press actions (also on playlists, history, ...)), so basically nowhere / passing checkstyle * assimilated the enqueue*OnPlayer methods * removed redundant comment, variable * simplify code line Co-authored-by: Stypox <stypox@pm.me> * move if * replace workaround for isPlayerOpen() Co-authored-by: Stypox <stypox@pm.me> * replaced workarounds (getType), corrected static access with getInstance * remove unused imports * changed method call to original, new method doesnt exist yet. * Use getter method instead of property access syntax. * improve conditional for play next entry Co-authored-by: Stypox <stypox@pm.me> * show play next btn in feed fragment Co-authored-by: Stypox <stypox@pm.me> * add play next to local playlist and statistics fragment Co-authored-by: Stypox <stypox@pm.me> * formating Co-authored-by: Stypox <stypox@pm.me> * correcting logic Co-authored-by: Stypox <stypox@pm.me> * remove 2 year old unused string, formating Co-authored-by: Stypox <stypox@pm.me> * correct enqueue (next) conditionals, default to background if no player is open. Dont generally default to background play. * remove player open checks from button long press enqueue actions * improve log msg * Rename next to enqueue_next * Refactor kotlin Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> Co-authored-by: Stypox <stypox@pm.me>
2021-09-18 11:22:49 +02:00
import org.schabi.newpipe.player.MainPlayer.PlayerType;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
2020-10-31 21:55:45 +01:00
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Action;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
implements View.OnClickListener {
private static final int BUTTON_DEBOUNCE_INTERVAL = 100;
private static final String PICASSO_CHANNEL_TAG = "PICASSO_CHANNEL_TAG";
private final CompositeDisposable disposables = new CompositeDisposable();
private Disposable subscribeButtonMonitor;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private SubscriptionManager subscriptionManager;
2020-11-03 06:26:29 +01:00
private FragmentChannelBinding channelBinding;
private ChannelHeaderBinding headerBinding;
private PlaylistControlBinding playlistControlBinding;
private MenuItem menuRssButton;
public static ChannelFragment getInstance(final int serviceId, final String url,
final String name) {
2020-08-16 10:24:58 +02:00
final ChannelFragment instance = new ChannelFragment();
instance.setInitialData(serviceId, url, name);
return instance;
}
public ChannelFragment() {
super(UserAction.REQUESTED_CHANNEL);
}
2017-10-26 20:45:16 +02:00
@Override
2021-10-16 21:33:45 +02:00
public void onResume() {
super.onResume();
if (activity != null && useAsFrontPage) {
setTitle(currentInfo != null ? currentInfo.getName() : name);
2017-10-26 20:45:16 +02:00
}
}
2020-04-02 13:51:10 +02:00
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
subscriptionManager = new SubscriptionManager(activity);
}
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_channel, container, false);
}
@Override
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
2020-11-03 06:26:29 +01:00
channelBinding = FragmentChannelBinding.bind(rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
disposables.clear();
if (subscribeButtonMonitor != null) {
subscribeButtonMonitor.dispose();
}
2020-11-03 06:26:29 +01:00
channelBinding = null;
headerBinding = null;
playlistControlBinding = null;
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
protected ViewBinding getListHeader() {
headerBinding = ChannelHeaderBinding
.inflate(activity.getLayoutInflater(), itemsList, false);
playlistControlBinding = headerBinding.playlistControl;
return headerBinding;
}
@Override
protected void initListeners() {
super.initListeners();
headerBinding.subChannelTitleView.setOnClickListener(this);
headerBinding.subChannelAvatarView.setOnClickListener(this);
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
2020-08-16 10:24:58 +02:00
final ActionBar supportActionBar = activity.getSupportActionBar();
2019-11-23 20:04:40 +01:00
if (useAsFrontPage && supportActionBar != null) {
2017-09-26 18:16:39 +02:00
supportActionBar.setDisplayHomeAsUpEnabled(false);
} else {
inflater.inflate(R.menu.menu_channel, menu);
if (DEBUG) {
Log.d(TAG, "onCreateOptionsMenu() called with: "
+ "menu = [" + menu + "], inflater = [" + inflater + "]");
}
2017-09-26 18:16:39 +02:00
menuRssButton = menu.findItem(R.id.menu_item_rss);
}
}
private void openRssFeed() {
final ChannelInfo info = currentInfo;
2019-11-23 20:04:40 +01:00
if (info != null) {
ShareUtils.openUrlInBrowser(requireContext(), info.getFeedUrl(), false);
}
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
2020-02-22 10:36:10 +01:00
case R.id.action_settings:
NavigationHelper.openSettings(requireContext());
break;
case R.id.menu_item_rss:
openRssFeed();
break;
case R.id.menu_item_openInBrowser:
2019-12-02 21:34:52 +01:00
if (currentInfo != null) {
2020-02-22 10:36:10 +01:00
ShareUtils.openUrlInBrowser(requireContext(), currentInfo.getOriginalUrl());
2019-12-02 21:34:52 +01:00
}
break;
case R.id.menu_item_share:
2019-12-02 21:34:52 +01:00
if (currentInfo != null) {
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
currentInfo.getAvatarUrl());
2019-12-02 21:34:52 +01:00
}
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Channel Subscription
//////////////////////////////////////////////////////////////////////////*/
private void monitorSubscription(final ChannelInfo info) {
final Consumer<Throwable> onError = (Throwable throwable) -> {
animate(headerBinding.channelSubscribeButton, false, 100);
showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_GET,
"Get subscription status", currentInfo));
};
final Observable<List<SubscriptionEntity>> observable = subscriptionManager
.subscriptionTable()
.getSubscriptionFlowable(info.getServiceId(), info.getUrl())
.toObservable();
disposables.add(observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getSubscribeUpdateMonitor(info), onError));
disposables.add(observable
// Some updates are very rapid
// (for example when calling the updateSubscription(info))
// so only update the UI for the latest emission
// ("sync" the subscribe button's state)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe((List<SubscriptionEntity> subscriptionEntities) ->
updateSubscribeButton(!subscriptionEntities.isEmpty()), onError));
}
private Function<Object, Object> mapOnSubscribe(final SubscriptionEntity subscription,
final ChannelInfo info) {
return (@NonNull Object o) -> {
subscriptionManager.insertSubscription(subscription, info);
return o;
};
}
private Function<Object, Object> mapOnUnsubscribe(final SubscriptionEntity subscription) {
return (@NonNull Object o) -> {
subscriptionManager.deleteSubscription(subscription);
return o;
};
}
private void updateSubscription(final ChannelInfo info) {
if (DEBUG) {
Log.d(TAG, "updateSubscription() called with: info = [" + info + "]");
}
final Action onComplete = () -> {
if (DEBUG) {
Log.d(TAG, "Updated subscription: " + info.getUrl());
}
};
final Consumer<Throwable> onError = (@NonNull Throwable throwable) ->
showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_UPDATE,
"Updating subscription for " + info.getUrl(), info));
disposables.add(subscriptionManager.updateChannelInfo(info)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onComplete, onError));
}
private Disposable monitorSubscribeButton(final Button subscribeButton,
final Function<Object, Object> action) {
final Consumer<Object> onNext = (@NonNull Object o) -> {
if (DEBUG) {
Log.d(TAG, "Changed subscription status to this channel!");
}
};
final Consumer<Throwable> onError = (@NonNull Throwable throwable) ->
showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_CHANGE,
"Changing subscription for " + currentInfo.getUrl(), currentInfo));
/* Emit clicks from main thread unto io thread */
return RxView.clicks(subscribeButton)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.io())
.debounce(BUTTON_DEBOUNCE_INTERVAL, TimeUnit.MILLISECONDS) // Ignore rapid clicks
.map(action)
.subscribe(onNext, onError);
}
private Consumer<List<SubscriptionEntity>> getSubscribeUpdateMonitor(final ChannelInfo info) {
return (List<SubscriptionEntity> subscriptionEntities) -> {
if (DEBUG) {
Log.d(TAG, "subscriptionManager.subscriptionTable.doOnNext() called with: "
+ "subscriptionEntities = [" + subscriptionEntities + "]");
}
if (subscribeButtonMonitor != null) {
subscribeButtonMonitor.dispose();
}
if (subscriptionEntities.isEmpty()) {
if (DEBUG) {
Log.d(TAG, "No subscription to this channel!");
}
2020-08-16 10:24:58 +02:00
final SubscriptionEntity channel = new SubscriptionEntity();
channel.setServiceId(info.getServiceId());
channel.setUrl(info.getUrl());
channel.setData(info.getName(),
info.getAvatarUrl(),
info.getDescription(),
info.getSubscriberCount());
subscribeButtonMonitor = monitorSubscribeButton(
headerBinding.channelSubscribeButton, mapOnSubscribe(channel, info));
} else {
if (DEBUG) {
Log.d(TAG, "Found subscription to this channel!");
}
final SubscriptionEntity subscription = subscriptionEntities.get(0);
subscribeButtonMonitor = monitorSubscribeButton(
headerBinding.channelSubscribeButton, mapOnUnsubscribe(subscription));
}
};
}
private void updateSubscribeButton(final boolean isSubscribed) {
if (DEBUG) {
Log.d(TAG, "updateSubscribeButton() called with: "
+ "isSubscribed = [" + isSubscribed + "]");
}
final boolean isButtonVisible = headerBinding.channelSubscribeButton.getVisibility()
== View.VISIBLE;
2020-08-16 10:24:58 +02:00
final int backgroundDuration = isButtonVisible ? 300 : 0;
final int textDuration = isButtonVisible ? 200 : 0;
2020-08-16 10:24:58 +02:00
final int subscribeBackground = ThemeHelper
.resolveColorFromAttr(activity, R.attr.colorPrimary);
2020-08-16 10:24:58 +02:00
final int subscribeText = ContextCompat.getColor(activity, R.color.subscribe_text_color);
final int subscribedBackground = ContextCompat
.getColor(activity, R.color.subscribed_background_color);
2020-08-16 10:24:58 +02:00
final int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color);
if (!isSubscribed) {
headerBinding.channelSubscribeButton.setText(R.string.subscribe_button_title);
animateBackgroundColor(headerBinding.channelSubscribeButton, backgroundDuration,
subscribedBackground, subscribeBackground);
animateTextColor(headerBinding.channelSubscribeButton, textDuration, subscribedText,
subscribeText);
} else {
headerBinding.channelSubscribeButton.setText(R.string.subscribed_button_title);
animateBackgroundColor(headerBinding.channelSubscribeButton, backgroundDuration,
subscribeBackground, subscribedBackground);
animateTextColor(headerBinding.channelSubscribeButton, textDuration, subscribeText,
subscribedText);
}
animate(headerBinding.channelSubscribeButton, true, 100,
AnimationType.LIGHT_SCALE_AND_ALPHA);
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@Override
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
return ExtractorHelper.getMoreChannelItems(serviceId, url, currentNextPage);
}
@Override
protected Single<ChannelInfo> loadResult(final boolean forceLoad) {
return ExtractorHelper.getChannelInfo(serviceId, url, forceLoad);
}
/*//////////////////////////////////////////////////////////////////////////
// OnClick
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onClick(final View v) {
if (isLoading.get() || currentInfo == null) {
return;
}
switch (v.getId()) {
case R.id.sub_channel_avatar_view:
case R.id.sub_channel_title_view:
2020-05-08 18:03:19 +02:00
if (!TextUtils.isEmpty(currentInfo.getParentChannelUrl())) {
try {
NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(),
currentInfo.getParentChannelUrl(),
2020-05-08 18:03:19 +02:00
currentInfo.getParentChannelName());
2020-08-16 10:24:58 +02:00
} catch (final Exception e) {
ErrorActivity.reportUiErrorInSnackbar(this, "Opening channel fragment", e);
}
2020-05-08 18:03:19 +02:00
} else if (DEBUG) {
Log.i(TAG, "Can't open parent channel because we got no channel URL");
}
break;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
PicassoHelper.cancelTag(PICASSO_CHANNEL_TAG);
animate(headerBinding.channelSubscribeButton, false, 100);
}
@Override
public void handleResult(@NonNull final ChannelInfo result) {
super.handleResult(result);
headerBinding.getRoot().setVisibility(View.VISIBLE);
PicassoHelper.loadBanner(result.getBannerUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.channelBannerImage);
PicassoHelper.loadAvatar(result.getAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.channelAvatarView);
PicassoHelper.loadAvatar(result.getParentChannelAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
.into(headerBinding.subChannelAvatarView);
headerBinding.channelSubscriberView.setVisibility(View.VISIBLE);
if (result.getSubscriberCount() >= 0) {
headerBinding.channelSubscriberView.setText(Localization
.shortSubscriberCount(activity, result.getSubscriberCount()));
} else {
headerBinding.channelSubscriberView.setText(R.string.subscribers_count_not_available);
}
2020-05-08 18:03:19 +02:00
if (!TextUtils.isEmpty(currentInfo.getParentChannelName())) {
headerBinding.subChannelTitleView.setText(String.format(
getString(R.string.channel_created_by),
currentInfo.getParentChannelName())
);
headerBinding.subChannelTitleView.setVisibility(View.VISIBLE);
headerBinding.subChannelAvatarView.setVisibility(View.VISIBLE);
} else {
headerBinding.subChannelTitleView.setVisibility(View.GONE);
}
if (menuRssButton != null) {
menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl()));
}
// PlaylistControls should be visible only if there is some item in
// infoListAdapter other than header
if (infoListAdapter.getItemCount() != 1) {
playlistControlBinding.getRoot().setVisibility(View.VISIBLE);
} else {
playlistControlBinding.getRoot().setVisibility(View.GONE);
}
for (final Throwable throwable : result.getErrors()) {
if (throwable instanceof ContentNotSupportedException) {
showContentNotSupported();
}
}
disposables.clear();
if (subscribeButtonMonitor != null) {
subscribeButtonMonitor.dispose();
}
updateSubscription(result);
monitorSubscription(result);
playlistControlBinding.playlistCtrlPlayAllButton
.setOnClickListener(view -> NavigationHelper
.playOnMainPlayer(activity, getPlayQueue()));
playlistControlBinding.playlistCtrlPlayPopupButton
.setOnClickListener(view -> NavigationHelper
.playOnPopupPlayer(activity, getPlayQueue(), false));
playlistControlBinding.playlistCtrlPlayBgButton
.setOnClickListener(view -> NavigationHelper
.playOnBackgroundPlayer(activity, getPlayQueue(), false));
playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> {
Add play next to long press menu & refactor enqueue methods (#6872) * added mvp play next button in long press menu; new intent handling, new long press dialog entry, new dialog functions, new strings * changed line length for checkstyle pass * cleaned comments, moved strings * Update app/src/main/res/values/strings.xml to make long press entry more descriptive Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> * Update app/src/main/res/values/strings.xml Co-authored-by: Stypox <stypox@pm.me> * replace redundant nextOnVideoPlayer methods Co-authored-by: Stypox <stypox@pm.me> * add enqueueNextOnPlayer and enqueueOnPlayer without selectOnAppend and RESUME_PLAYBACK/ deprecate enqueueNextOn*Player and enqueueOn*Player methods add getPlayerIntent, getPlayerEnqueueIntent and getPlayerEnqueueNextIntent without selectOnAppend and RESUME_PLAYBACK/ deprecate those with add section comments * removed deprecated methods removed redundant methods * removed deprecated methods removed redundant methods * replaced APPEND_ONLY, removed SELECT_ON_APPEND / replaced remaining enqueueOn*Player methods * now works with playlists * renamed dialog entry * checking for >1 items in the queue using the PlayerHolder * making enqueue*OnPlayer safe to call when no video is playing (defaulting to audio) * corrected strings * improve getQueueSize in PlayerHolder * long press to enqueue only if queue isnt empty * add Whitespace Co-authored-by: Stypox <stypox@pm.me> * clarify comments / add spaces * PlayerType as parameter of the enqueueOnPlayer method add Helper method * using the helper function everywhere (except for the background and popup long-press actions (also on playlists, history, ...)), so basically nowhere / passing checkstyle * assimilated the enqueue*OnPlayer methods * removed redundant comment, variable * simplify code line Co-authored-by: Stypox <stypox@pm.me> * move if * replace workaround for isPlayerOpen() Co-authored-by: Stypox <stypox@pm.me> * replaced workarounds (getType), corrected static access with getInstance * remove unused imports * changed method call to original, new method doesnt exist yet. * Use getter method instead of property access syntax. * improve conditional for play next entry Co-authored-by: Stypox <stypox@pm.me> * show play next btn in feed fragment Co-authored-by: Stypox <stypox@pm.me> * add play next to local playlist and statistics fragment Co-authored-by: Stypox <stypox@pm.me> * formating Co-authored-by: Stypox <stypox@pm.me> * correcting logic Co-authored-by: Stypox <stypox@pm.me> * remove 2 year old unused string, formating Co-authored-by: Stypox <stypox@pm.me> * correct enqueue (next) conditionals, default to background if no player is open. Dont generally default to background play. * remove player open checks from button long press enqueue actions * improve log msg * Rename next to enqueue_next * Refactor kotlin Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> Co-authored-by: Stypox <stypox@pm.me>
2021-09-18 11:22:49 +02:00
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.POPUP);
return true;
});
playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> {
Add play next to long press menu & refactor enqueue methods (#6872) * added mvp play next button in long press menu; new intent handling, new long press dialog entry, new dialog functions, new strings * changed line length for checkstyle pass * cleaned comments, moved strings * Update app/src/main/res/values/strings.xml to make long press entry more descriptive Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> * Update app/src/main/res/values/strings.xml Co-authored-by: Stypox <stypox@pm.me> * replace redundant nextOnVideoPlayer methods Co-authored-by: Stypox <stypox@pm.me> * add enqueueNextOnPlayer and enqueueOnPlayer without selectOnAppend and RESUME_PLAYBACK/ deprecate enqueueNextOn*Player and enqueueOn*Player methods add getPlayerIntent, getPlayerEnqueueIntent and getPlayerEnqueueNextIntent without selectOnAppend and RESUME_PLAYBACK/ deprecate those with add section comments * removed deprecated methods removed redundant methods * removed deprecated methods removed redundant methods * replaced APPEND_ONLY, removed SELECT_ON_APPEND / replaced remaining enqueueOn*Player methods * now works with playlists * renamed dialog entry * checking for >1 items in the queue using the PlayerHolder * making enqueue*OnPlayer safe to call when no video is playing (defaulting to audio) * corrected strings * improve getQueueSize in PlayerHolder * long press to enqueue only if queue isnt empty * add Whitespace Co-authored-by: Stypox <stypox@pm.me> * clarify comments / add spaces * PlayerType as parameter of the enqueueOnPlayer method add Helper method * using the helper function everywhere (except for the background and popup long-press actions (also on playlists, history, ...)), so basically nowhere / passing checkstyle * assimilated the enqueue*OnPlayer methods * removed redundant comment, variable * simplify code line Co-authored-by: Stypox <stypox@pm.me> * move if * replace workaround for isPlayerOpen() Co-authored-by: Stypox <stypox@pm.me> * replaced workarounds (getType), corrected static access with getInstance * remove unused imports * changed method call to original, new method doesnt exist yet. * Use getter method instead of property access syntax. * improve conditional for play next entry Co-authored-by: Stypox <stypox@pm.me> * show play next btn in feed fragment Co-authored-by: Stypox <stypox@pm.me> * add play next to local playlist and statistics fragment Co-authored-by: Stypox <stypox@pm.me> * formating Co-authored-by: Stypox <stypox@pm.me> * correcting logic Co-authored-by: Stypox <stypox@pm.me> * remove 2 year old unused string, formating Co-authored-by: Stypox <stypox@pm.me> * correct enqueue (next) conditionals, default to background if no player is open. Dont generally default to background play. * remove player open checks from button long press enqueue actions * improve log msg * Rename next to enqueue_next * Refactor kotlin Co-authored-by: opusforlife2 <53176348+opusforlife2@users.noreply.github.com> Co-authored-by: Stypox <stypox@pm.me>
2021-09-18 11:22:49 +02:00
NavigationHelper.enqueueOnPlayer(activity, getPlayQueue(), PlayerType.AUDIO);
return true;
});
}
private void showContentNotSupported() {
2020-11-03 06:26:29 +01:00
channelBinding.errorContentNotSupported.setVisibility(View.VISIBLE);
channelBinding.channelKaomoji.setText("(︶︹︺)");
channelBinding.channelKaomoji.setTextSize(TypedValue.COMPLEX_UNIT_SP, 45f);
channelBinding.channelNoVideos.setVisibility(View.GONE);
}
private PlayQueue getPlayQueue() {
return getPlayQueue(0);
}
private PlayQueue getPlayQueue(final int index) {
final List<StreamInfoItem> streamItems = new ArrayList<>();
2020-08-16 10:24:58 +02:00
for (final InfoItem i : infoListAdapter.getItemsList()) {
2019-11-23 20:04:40 +01:00
if (i instanceof StreamInfoItem) {
streamItems.add((StreamInfoItem) i);
}
}
return new ChannelPlayQueue(currentInfo.getServiceId(), currentInfo.getUrl(),
currentInfo.getNextPage(), streamItems, index);
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setTitle(final String title) {
super.setTitle(title);
if (!useAsFrontPage) {
headerBinding.channelTitleView.setText(title);
}
}
}