2017-09-03 08:04:18 +02:00
|
|
|
package org.schabi.newpipe.fragments.list.channel;
|
|
|
|
|
2022-10-23 11:28:34 +02:00
|
|
|
import android.content.Context;
|
2017-09-03 08:04:18 +02:00
|
|
|
import android.os.Bundle;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuInflater;
|
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
import org.schabi.newpipe.R;
|
2022-10-23 11:28:34 +02:00
|
|
|
import org.schabi.newpipe.database.subscription.NotificationMode;
|
|
|
|
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
2020-11-03 06:26:29 +01:00
|
|
|
import org.schabi.newpipe.databinding.FragmentChannelBinding;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.error.ErrorInfo;
|
|
|
|
import org.schabi.newpipe.error.UserAction;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
2022-10-23 15:37:40 +02:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
2022-10-23 10:27:35 +02:00
|
|
|
import org.schabi.newpipe.extractor.linkhandler.ChannelTabHandler;
|
|
|
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
|
|
|
import org.schabi.newpipe.fragments.detail.TabAdapter;
|
2022-10-23 11:28:34 +02:00
|
|
|
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
|
|
|
|
import org.schabi.newpipe.local.subscription.SubscriptionManager;
|
2022-10-23 10:27:35 +02:00
|
|
|
import org.schabi.newpipe.util.Constants;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.util.ExtractorHelper;
|
2017-11-04 19:30:01 +01:00
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
2022-01-16 17:08:13 +01:00
|
|
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 11:28:34 +02:00
|
|
|
import java.util.List;
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
import icepick.State;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
2022-10-23 11:28:34 +02:00
|
|
|
import io.reactivex.rxjava3.core.Observable;
|
|
|
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.disposables.Disposable;
|
2022-10-23 11:28:34 +02:00
|
|
|
import io.reactivex.rxjava3.functions.Consumer;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
public class ChannelFragment extends BaseStateFragment<ChannelInfo> {
|
|
|
|
@State
|
|
|
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
|
|
|
@State
|
|
|
|
protected String name;
|
|
|
|
@State
|
|
|
|
protected String url;
|
2021-03-27 14:37:44 +01:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private ChannelInfo currentInfo;
|
|
|
|
private Disposable currentWorker;
|
2022-10-23 11:28:34 +02:00
|
|
|
private Disposable subscriptionMonitor;
|
|
|
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
|
|
private SubscriptionManager subscriptionManager;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private MenuItem menuRssButton;
|
2022-10-23 11:28:34 +02:00
|
|
|
private MenuItem menuNotifyButton;
|
2022-04-04 17:58:39 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Views
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private FragmentChannelBinding binding;
|
|
|
|
private TabAdapter tabAdapter;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
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();
|
2018-07-10 16:26:42 +02:00
|
|
|
instance.setInitialData(serviceId, url, name);
|
2017-09-03 08:04:18 +02:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
public ChannelFragment() {
|
2022-10-23 10:27:35 +02:00
|
|
|
super();
|
2020-12-11 14:55:47 +01:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
protected void setInitialData(final int sid, final String u, final String title) {
|
|
|
|
this.serviceId = sid;
|
|
|
|
this.url = u;
|
|
|
|
this.name = !TextUtils.isEmpty(title) ? title : "";
|
2017-10-26 20:45:16 +02:00
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// LifeCycle
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2022-10-23 10:27:35 +02:00
|
|
|
public void onCreate(final Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setHasOptionsMenu(true);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 11:28:34 +02:00
|
|
|
@Override
|
|
|
|
public void onAttach(@NonNull Context context) {
|
|
|
|
super.onAttach(context);
|
|
|
|
subscriptionManager = new SubscriptionManager(activity);
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public View onCreateView(@NonNull final LayoutInflater inflater,
|
|
|
|
@Nullable final ViewGroup container,
|
|
|
|
@Nullable final Bundle savedInstanceState) {
|
2022-10-23 10:27:35 +02:00
|
|
|
binding = FragmentChannelBinding.inflate(inflater, container, false);
|
|
|
|
return binding.getRoot();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
@Override // called from onViewCreated in {@link BaseFragment#onViewCreated}
|
|
|
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
|
|
|
super.initViews(rootView, savedInstanceState);
|
|
|
|
|
|
|
|
tabAdapter = new TabAdapter(getChildFragmentManager());
|
|
|
|
binding.viewPager.setAdapter(tabAdapter);
|
|
|
|
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
2020-04-07 15:39:06 +02:00
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2022-10-23 11:28:34 +02:00
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
|
|
|
if (subscriptionMonitor != null) {
|
|
|
|
subscriptionMonitor.dispose();
|
|
|
|
}
|
|
|
|
disposables.clear();
|
2022-10-23 10:27:35 +02:00
|
|
|
binding = null;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-09-03 08:04:18 +02:00
|
|
|
// Menu
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2021-06-20 00:29:18 +02:00
|
|
|
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
|
|
|
@NonNull final MenuInflater inflater) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.onCreateOptionsMenu(menu, inflater);
|
2022-10-23 10:27:35 +02:00
|
|
|
inflater.inflate(R.menu.menu_channel, menu);
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onCreateOptionsMenu() called with: "
|
|
|
|
+ "menu = [" + menu + "], inflater = [" + inflater + "]");
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2022-10-23 10:27:35 +02:00
|
|
|
menuRssButton = menu.findItem(R.id.menu_item_rss);
|
2022-10-23 11:28:34 +02:00
|
|
|
menuNotifyButton = menu.findItem(R.id.menu_item_notify);
|
2022-10-23 10:27:35 +02:00
|
|
|
updateRssButton();
|
2022-10-23 11:28:34 +02:00
|
|
|
monitorSubscription();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
2017-09-03 08:04:18 +02:00
|
|
|
switch (item.getItemId()) {
|
2022-10-23 11:28:34 +02:00
|
|
|
case R.id.menu_item_notify:
|
|
|
|
final boolean value = !item.isChecked();
|
|
|
|
item.setEnabled(false);
|
|
|
|
setNotify(value);
|
|
|
|
break;
|
2020-02-22 10:36:10 +01:00
|
|
|
case R.id.action_settings:
|
|
|
|
NavigationHelper.openSettings(requireContext());
|
|
|
|
break;
|
2017-11-01 16:26:44 +01:00
|
|
|
case R.id.menu_item_rss:
|
2022-01-15 23:55:19 +01:00
|
|
|
if (currentInfo != null) {
|
2023-02-23 23:38:20 +01:00
|
|
|
ShareUtils.openUrlInApp(requireContext(), currentInfo.getFeedUrl());
|
2022-01-15 23:55:19 +01:00
|
|
|
}
|
2017-11-01 16:26:44 +01:00
|
|
|
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
|
|
|
}
|
2017-11-01 16:26:44 +01:00
|
|
|
break;
|
2018-01-29 08:01:06 +01:00
|
|
|
case R.id.menu_item_share:
|
2019-12-02 21:34:52 +01:00
|
|
|
if (currentInfo != null) {
|
2021-03-20 16:35:14 +01:00
|
|
|
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
|
|
|
|
currentInfo.getAvatarUrl());
|
2019-12-02 21:34:52 +01:00
|
|
|
}
|
2017-11-01 16:26:44 +01:00
|
|
|
break;
|
2017-09-03 08:04:18 +02:00
|
|
|
default:
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
|
|
}
|
2017-11-01 16:26:44 +01:00
|
|
|
return true;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private void updateRssButton() {
|
|
|
|
if (currentInfo != null && menuRssButton != null) {
|
|
|
|
menuRssButton.setVisible(!TextUtils.isEmpty(currentInfo.getFeedUrl()));
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2022-10-23 10:27:35 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 11:28:34 +02:00
|
|
|
private void monitorSubscription() {
|
|
|
|
if (currentInfo != null) {
|
|
|
|
final Observable<List<SubscriptionEntity>> observable = subscriptionManager
|
|
|
|
.subscriptionTable()
|
|
|
|
.getSubscriptionFlowable(currentInfo.getServiceId(), currentInfo.getUrl())
|
|
|
|
.toObservable();
|
|
|
|
|
|
|
|
if (subscriptionMonitor != null) {
|
|
|
|
subscriptionMonitor.dispose();
|
|
|
|
}
|
|
|
|
subscriptionMonitor = observable
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(getSubscribeUpdateMonitor());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Consumer<List<SubscriptionEntity>> getSubscribeUpdateMonitor() {
|
|
|
|
return (List<SubscriptionEntity> subscriptionEntities) -> {
|
|
|
|
if (subscriptionEntities.isEmpty()) {
|
|
|
|
updateNotifyButton(null);
|
|
|
|
} else {
|
|
|
|
final SubscriptionEntity subscription = subscriptionEntities.get(0);
|
|
|
|
updateNotifyButton(subscription);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateNotifyButton(@Nullable final SubscriptionEntity subscription) {
|
|
|
|
if (menuNotifyButton == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (subscription != null) {
|
|
|
|
menuNotifyButton.setEnabled(
|
|
|
|
NotificationHelper.areNewStreamsNotificationsEnabled(requireContext())
|
|
|
|
);
|
|
|
|
menuNotifyButton.setChecked(
|
|
|
|
subscription.getNotificationMode() == NotificationMode.ENABLED
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
menuNotifyButton.setVisible(subscription != null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setNotify(final boolean isEnabled) {
|
|
|
|
disposables.add(
|
|
|
|
subscriptionManager
|
|
|
|
.updateNotificationMode(
|
|
|
|
currentInfo.getServiceId(),
|
|
|
|
currentInfo.getUrl(),
|
|
|
|
isEnabled ? NotificationMode.ENABLED : NotificationMode.DISABLED)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Init
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 15:37:40 +02:00
|
|
|
private boolean isContentUnsupported() {
|
|
|
|
for (final Throwable throwable : currentInfo.getErrors()) {
|
|
|
|
if (throwable instanceof ContentNotSupportedException) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private void updateTabs() {
|
|
|
|
tabAdapter.clearAllItems();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
if (currentInfo != null) {
|
2022-10-23 15:37:40 +02:00
|
|
|
if (isContentUnsupported()) {
|
|
|
|
showEmptyState();
|
|
|
|
binding.errorContentNotSupported.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
2022-10-23 10:27:35 +02:00
|
|
|
tabAdapter.addFragment(
|
2022-10-23 15:37:40 +02:00
|
|
|
ChannelVideosFragment.getInstance(currentInfo), "Videos");
|
2018-08-22 16:04:32 +02:00
|
|
|
|
2022-10-23 15:37:40 +02:00
|
|
|
for (final ChannelTabHandler tab : currentInfo.getTabs()) {
|
|
|
|
tabAdapter.addFragment(
|
|
|
|
ChannelTabFragment.getInstance(serviceId, tab), tab.getTab().name());
|
|
|
|
}
|
|
|
|
|
|
|
|
final String description = currentInfo.getDescription();
|
|
|
|
if (description != null && !description.isEmpty()) {
|
|
|
|
tabAdapter.addFragment(
|
2022-10-23 17:01:39 +02:00
|
|
|
ChannelInfoFragment.getInstance(currentInfo), "Info");
|
2022-10-23 15:37:40 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
tabAdapter.notifyDataSetUpdate();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
for (int i = 0; i < tabAdapter.getCount(); i++) {
|
|
|
|
binding.tabLayout.getTabAt(i).setText(tabAdapter.getItemTitle(i));
|
2019-05-08 19:17:54 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-10-23 10:27:35 +02:00
|
|
|
public void startLoading(final boolean forceLoad) {
|
|
|
|
super.startLoading(forceLoad);
|
2020-04-13 22:40:58 +02:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
currentInfo = null;
|
|
|
|
updateTabs();
|
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
2020-04-13 22:40:58 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
runWorker(forceLoad);
|
2020-04-13 22:40:58 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
private void runWorker(final boolean forceLoad) {
|
|
|
|
currentWorker = ExtractorHelper.getChannelInfo(serviceId, url, forceLoad)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(result -> {
|
|
|
|
isLoading.set(false);
|
|
|
|
handleResult(result);
|
|
|
|
}, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_STREAM,
|
|
|
|
url == null ? "no url" : url, serviceId)));
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-10-23 15:37:40 +02:00
|
|
|
public void handleResult(@NonNull final ChannelInfo result) {
|
|
|
|
super.handleResult(result);
|
|
|
|
currentInfo = result;
|
|
|
|
setInitialData(result.getServiceId(), result.getOriginalUrl(), result.getName());
|
2018-01-29 08:01:06 +01:00
|
|
|
|
2022-10-23 10:27:35 +02:00
|
|
|
updateTabs();
|
|
|
|
updateRssButton();
|
2022-10-23 11:28:34 +02:00
|
|
|
monitorSubscription();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
}
|