diff --git a/app/src/main/java/org/schabi/newpipe/fragments/subscription/SubscriptionFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/subscription/SubscriptionFragment.java index afcb03d2b..520586663 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/subscription/SubscriptionFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/subscription/SubscriptionFragment.java @@ -1,21 +1,21 @@ package org.schabi.newpipe.fragments.subscription; +import android.content.Context; import android.os.Bundle; import android.os.Parcelable; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; -import org.schabi.newpipe.fragments.BaseFragment; +import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.report.UserAction; @@ -23,37 +23,32 @@ import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.NavigationHelper; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import icepick.State; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import static org.schabi.newpipe.report.UserAction.REQUESTED_CHANNEL; import static org.schabi.newpipe.util.AnimationUtils.animateView; -public class SubscriptionFragment extends BaseFragment { - private static final String VIEW_STATE_KEY = "view_state_key"; - private final String TAG = "SubscriptionFragment@" + Integer.toHexString(hashCode()); - - private View inflatedView; - private View emptyPanel; +public class SubscriptionFragment extends BaseStateFragment> { private View headerRootLayout; - private View whatsNewView; private InfoListAdapter infoListAdapter; - private RecyclerView resultRecyclerView; - private Parcelable viewState; + private RecyclerView itemsList; + + @State + protected Parcelable itemsListState; /* Used for independent events */ - private CompositeDisposable disposables; - private SubscriptionEngine subscriptionEngine; + private CompositeDisposable disposables = new CompositeDisposable(); + private SubscriptionService subscriptionService; /////////////////////////////////////////////////////////////////////////// // Fragment LifeCycle @@ -71,15 +66,10 @@ public class SubscriptionFragment extends BaseFragment { @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - disposables = new CompositeDisposable(); - subscriptionEngine = SubscriptionEngine.getInstance( getContext() ); - - if (savedInstanceState != null) { - viewState = savedInstanceState.getParcelable(VIEW_STATE_KEY); - } + public void onAttach(Context context) { + super.onAttach(context); + infoListAdapter = new InfoListAdapter(activity); + subscriptionService = SubscriptionService.getInstance(); } @Nullable @@ -94,19 +84,15 @@ public class SubscriptionFragment extends BaseFragment { } @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - outState.putParcelable(VIEW_STATE_KEY, viewState); + public void onPause() { + super.onPause(); + itemsListState = itemsList.getLayoutManager().onSaveInstanceState(); } @Override public void onDestroyView() { if (disposables != null) disposables.clear(); - headerRootLayout = null; - whatsNewView = null; - super.onDestroyView(); } @@ -114,8 +100,7 @@ public class SubscriptionFragment extends BaseFragment { public void onDestroy() { if (disposables != null) disposables.dispose(); disposables = null; - - subscriptionEngine = null; + subscriptionService = null; super.onDestroy(); } @@ -124,70 +109,39 @@ public class SubscriptionFragment extends BaseFragment { // Fragment Views /////////////////////////////////////////////////////////////////////////// - private RecyclerView.OnScrollListener getOnScrollListener() { - return new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - viewState = recyclerView.getLayoutManager().onSaveInstanceState(); - } - } - }; - } - - private View.OnClickListener getWhatsNewOnClickListener() { - return new View.OnClickListener() { - @Override - public void onClick(View view) { - NavigationHelper.openWhatsNewFragment(getParentFragment().getFragmentManager()); - } - }; - } - @Override protected void initViews(View rootView, Bundle savedInstanceState) { super.initViews(rootView, savedInstanceState); - emptyPanel = rootView.findViewById(R.id.empty_panel); + infoListAdapter = new InfoListAdapter(getActivity()); + itemsList = rootView.findViewById(R.id.items_list); + itemsList.setLayoutManager(new LinearLayoutManager(activity)); - resultRecyclerView = rootView.findViewById(R.id.result_list_view); - resultRecyclerView.setLayoutManager(new LinearLayoutManager(activity)); - resultRecyclerView.addOnScrollListener(getOnScrollListener()); + infoListAdapter.setHeader(headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, itemsList, false)); + infoListAdapter.useMiniItemVariants(true); - if (infoListAdapter == null) { - infoListAdapter = new InfoListAdapter(getActivity()); - infoListAdapter.setFooter(activity.getLayoutInflater().inflate(R.layout.pignate_footer, resultRecyclerView, false)); - infoListAdapter.showFooter(false); - infoListAdapter.setOnChannelInfoItemSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener() { - @Override - public void selected(int serviceId, String url, String title) { - /* Requires the parent fragment to find holder for fragment replacement */ - NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), serviceId, url, title); - } - }); - } - - headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, resultRecyclerView, false); - infoListAdapter.setHeader(headerRootLayout); - - whatsNewView = headerRootLayout.findViewById(R.id.whatsNew); - whatsNewView.setOnClickListener(getWhatsNewOnClickListener()); - - resultRecyclerView.setAdapter(infoListAdapter); - - populateView(); + itemsList.setAdapter(infoListAdapter); } @Override - protected void reloadContent() { - populateView(); - } + protected void initListeners() { + super.initListeners(); - @Override - protected void setErrorMessage(String message, boolean showRetryButton) { - super.setErrorMessage(message, showRetryButton); - resetFragment(); + infoListAdapter.setOnChannelSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener() { + @Override + public void selected(ChannelInfoItem selectedItem) { + // Requires the parent fragment to find holder for fragment replacement + NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(), selectedItem.service_id, selectedItem.url, selectedItem.name); + + } + }); + + headerRootLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + NavigationHelper.openWhatsNewFragment(getParentFragment().getFragmentManager()); + } + }); } private void resetFragment() { @@ -199,13 +153,12 @@ public class SubscriptionFragment extends BaseFragment { // Subscriptions Loader /////////////////////////////////////////////////////////////////////////// - private void populateView() { + @Override + public void startLoading(boolean forceLoad) { + super.startLoading(forceLoad); resetFragment(); - animateView(loadingProgressBar, true, 200); - animateView(errorPanel, false, 200); - - subscriptionEngine.getSubscription().toObservable() + subscriptionService.getSubscription().toObservable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscriptionObserver()); @@ -215,80 +168,91 @@ public class SubscriptionFragment extends BaseFragment { return new Observer>() { @Override public void onSubscribe(Disposable d) { - animateView(loadingProgressBar, true, 200); - - disposables.add( d ); + showLoading(); + disposables.add(d); } @Override public void onNext(List subscriptions) { - animateView(loadingProgressBar, true, 200); - - infoListAdapter.clearStreamItemList(); - infoListAdapter.addInfoItemList( getSubscriptionItems(subscriptions) ); - - animateView(loadingProgressBar, false, 200); - - emptyPanel.setVisibility(subscriptions.isEmpty() ? View.VISIBLE : View.INVISIBLE); - - if (viewState != null && resultRecyclerView != null) { - resultRecyclerView.getLayoutManager().onRestoreInstanceState(viewState); - } + handleResult(subscriptions); } @Override public void onError(Throwable exception) { - if (exception instanceof IOException) { - onRecoverableError(R.string.network_error); - } else { - onUnrecoverableError(exception); - } + SubscriptionFragment.this.onError(exception); } @Override public void onComplete() { - } }; } + @Override + public void handleResult(@NonNull List result) { + super.handleResult(result); + + infoListAdapter.clearStreamItemList(); + + if (result.isEmpty()) { + showEmptyState(); + } else { + infoListAdapter.addInfoItemList(getSubscriptionItems(result)); + if (itemsListState != null) { + itemsList.getLayoutManager().onRestoreInstanceState(itemsListState); + itemsListState = null; + } + + hideLoading(); + } + } + + private List getSubscriptionItems(List subscriptions) { List items = new ArrayList<>(); - for (final SubscriptionEntity subscription: subscriptions) { - ChannelInfoItem item = new ChannelInfoItem(); - item.webPageUrl = subscription.getUrl(); - item.serviceId = subscription.getServiceId(); - item.channelName = subscription.getTitle(); - item.thumbnailUrl = subscription.getThumbnailUrl(); - item.subscriberCount = subscription.getSubscriberCount(); - item.description = subscription.getDescription(); + for (final SubscriptionEntity subscription : subscriptions) items.add(subscription.toChannelInfoItem()); - items.add( item ); - } Collections.sort(items, new Comparator() { @Override public int compare(InfoItem o1, InfoItem o2) { - return o1.getTitle().compareToIgnoreCase(o2.getTitle()); + return o1.name.compareToIgnoreCase(o2.name); } }); - return items; } + /*////////////////////////////////////////////////////////////////////////// + // Contract + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void showLoading() { + super.showLoading(); + animateView(itemsList, false, 100); + } + + @Override + public void hideLoading() { + super.hideLoading(); + animateView(itemsList, true, 200); + } + + @Override + public void showEmptyState() { + super.showEmptyState(); + animateView(itemsList, false, 200); + } + /////////////////////////////////////////////////////////////////////////// // Fragment Error Handling /////////////////////////////////////////////////////////////////////////// - private void onRecoverableError(int messageId) { - if (!this.isAdded()) return; + @Override + protected boolean onError(Throwable exception) { + resetFragment(); + if (super.onError(exception)) return true; - if (DEBUG) Log.d(TAG, "onError() called with: messageId = [" + messageId + "]"); - setErrorMessage(getString(messageId), true); - } - - private void onUnrecoverableError(Throwable exception) { - if (DEBUG) Log.d(TAG, "onUnrecoverableError() called with: exception = [" + exception + "]"); - ErrorActivity.reportError(getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_CHANNEL, "unknown", "unknown", R.string.general_error)); - activity.finish(); + onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Subscriptions", R.string.general_error); + return true; } }