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

396 lines
14 KiB
Java
Raw Normal View History

package org.schabi.newpipe.fragments.list.channel;
import android.content.Context;
2022-10-23 21:13:43 +02:00
import android.content.SharedPreferences;
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;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
2022-10-23 21:13:43 +02:00
import androidx.preference.PreferenceManager;
import com.google.android.material.tabs.TabLayout;
import org.schabi.newpipe.R;
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;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
2022-10-23 15:37:40 +02:00
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
2022-10-23 10:27:35 +02:00
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.detail.TabAdapter;
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.util.ChannelTabHelper;
2022-10-23 10:27:35 +02:00
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
2022-10-25 09:01:11 +02:00
import org.schabi.newpipe.util.StateSaver;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.List;
2022-10-25 09:01:11 +02:00
import java.util.Queue;
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;
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;
import io.reactivex.rxjava3.functions.Consumer;
2020-10-31 21:55:45 +01:00
import io.reactivex.rxjava3.schedulers.Schedulers;
2022-10-25 09:01:11 +02:00
public class ChannelFragment extends BaseStateFragment<ChannelInfo>
implements StateSaver.WriteRead {
2022-10-23 10:27:35 +02:00
@State
protected int serviceId = Constants.NO_SERVICE_ID;
@State
protected String name;
@State
protected String url;
2022-10-23 10:27:35 +02:00
private ChannelInfo currentInfo;
private Disposable currentWorker;
private Disposable subscriptionMonitor;
private final CompositeDisposable disposables = new CompositeDisposable();
private SubscriptionManager subscriptionManager;
private int lastTab;
2022-10-23 10:27:35 +02:00
private MenuItem menuRssButton;
private MenuItem menuNotifyButton;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
2022-10-23 10:27:35 +02:00
private FragmentChannelBinding binding;
private TabAdapter tabAdapter;
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;
}
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
//////////////////////////////////////////////////////////////////////////*/
@Override
2022-10-23 10:27:35 +02:00
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
2022-11-22 02:52:25 +01:00
if (savedInstanceState != null) {
lastTab = savedInstanceState.getInt("LastTab");
} else {
lastTab = 0;
}
}
@Override
public void onAttach(final @NonNull 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) {
2022-10-23 10:27:35 +02:00
binding = FragmentChannelBinding.inflate(inflater, container, false);
return binding.getRoot();
}
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);
}
@Override
2022-11-22 02:52:25 +01:00
public void onSaveInstanceState(final @NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (binding != null) {
outState.putInt("LastTab", binding.tabLayout.getSelectedTabPosition());
}
2022-11-22 02:52:25 +01:00
}
@Override
public void onDestroy() {
super.onDestroy();
if (currentWorker != null) {
currentWorker.dispose();
}
if (subscriptionMonitor != null) {
subscriptionMonitor.dispose();
}
disposables.clear();
2022-10-23 10:27:35 +02:00
binding = null;
}
2022-10-23 10:27:35 +02:00
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) {
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 + "]");
}
2022-10-23 10:27:35 +02:00
menuRssButton = menu.findItem(R.id.menu_item_rss);
menuNotifyButton = menu.findItem(R.id.menu_item_notify);
2022-10-23 10:27:35 +02:00
updateRssButton();
monitorSubscription();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
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;
case R.id.menu_item_rss:
if (currentInfo != null) {
ShareUtils.openUrlInApp(requireContext(), currentInfo.getFeedUrl());
}
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;
}
2022-10-23 10:27:35 +02:00
private void updateRssButton() {
if (currentInfo != null && menuRssButton != null) {
menuRssButton.setVisible(!TextUtils.isEmpty(currentInfo.getFeedUrl()));
}
2022-10-23 10:27:35 +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
//////////////////////////////////////////////////////////////////////////*/
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();
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");
2022-10-23 21:13:43 +02:00
final Context context = getContext();
final SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(context);
for (final ListLinkHandler linkHandler : currentInfo.getTabs()) {
final String tab = linkHandler.getContentFilters().get(0);
if (ChannelTabHelper.showChannelTab(context, preferences, tab)) {
2022-10-23 21:13:43 +02:00
tabAdapter.addFragment(
2022-11-29 19:25:35 +01:00
ChannelTabFragment.getInstance(serviceId, linkHandler, name),
context.getString(ChannelTabHelper.getTranslationKey(tab)));
2022-10-23 21:13:43 +02:00
}
2022-10-23 15:37:40 +02:00
}
final String description = currentInfo.getDescription();
if (description != null && !description.isEmpty()
&& ChannelTabHelper.showChannelTab(
context, preferences, R.string.show_channel_tabs_about)) {
2022-10-23 15:37:40 +02:00
tabAdapter.addFragment(
ChannelAboutFragment.getInstance(currentInfo),
context.getString(R.string.channel_tab_about));
2022-10-23 15:37:40 +02:00
}
}
}
2022-10-23 10:27:35 +02:00
tabAdapter.notifyDataSetUpdate();
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
}
// Restore previously selected tab
final TabLayout.Tab ltab = binding.tabLayout.getTabAt(lastTab);
if (ltab != null) {
binding.tabLayout.selectTab(ltab);
}
}
2022-10-25 09:01:11 +02:00
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public String generateSuffix() {
return null;
}
@Override
public void writeTo(final Queue<Object> objectsToSave) {
objectsToSave.add(currentInfo);
if (binding != null) {
objectsToSave.add(binding.tabLayout.getSelectedTabPosition());
} else {
objectsToSave.add(0);
}
}
@Override
public void readFrom(@NonNull final Queue<Object> savedObjects) {
currentInfo = (ChannelInfo) savedObjects.poll();
lastTab = (Integer) savedObjects.poll();
}
@Override
protected void doInitialLoadLogic() {
if (currentInfo == null) {
startLoading(false);
} else {
handleResult(currentInfo);
}
}
@Override
2022-10-23 10:27:35 +02:00
public void startLoading(final boolean forceLoad) {
super.startLoading(forceLoad);
2022-10-23 10:27:35 +02:00
currentInfo = null;
updateTabs();
if (currentWorker != null) {
currentWorker.dispose();
}
2022-10-23 10:27:35 +02:00
runWorker(forceLoad);
}
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)));
}
@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());
2022-10-23 10:27:35 +02:00
updateTabs();
updateRssButton();
monitorSubscription();
}
}