put local foo into local foo folder
This commit is contained in:
parent
e319caec03
commit
22725316d3
16 changed files with 37 additions and 41 deletions
|
|
@ -27,10 +27,10 @@ import org.schabi.newpipe.extractor.ServiceList;
|
|||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.kiosk.KioskList;
|
||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||
import org.schabi.newpipe.fragments.list.feed.FeedFragment;
|
||||
import org.schabi.newpipe.local.feed.FeedFragment;
|
||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||
import org.schabi.newpipe.fragments.local.bookmark.BookmarkFragment;
|
||||
import org.schabi.newpipe.fragments.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ import org.schabi.newpipe.extractor.ListExtractor;
|
|||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.stream.Stream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog;
|
||||
|
|
@ -42,7 +40,7 @@ import org.schabi.newpipe.playlist.ChannelPlayQueue;
|
|||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.subscription.SubscriptionService;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||
|
|
|
|||
|
|
@ -1,448 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.list.feed;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.subscription.SubscriptionService;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.MaybeObserver;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.functions.Predicate;
|
||||
|
||||
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {
|
||||
|
||||
private static final int OFF_SCREEN_ITEMS_COUNT = 3;
|
||||
private static final int MIN_ITEMS_INITIAL_LOAD = 8;
|
||||
private int FEED_LOAD_COUNT = MIN_ITEMS_INITIAL_LOAD;
|
||||
|
||||
private int subscriptionPoolSize;
|
||||
|
||||
private SubscriptionService subscriptionService;
|
||||
|
||||
private AtomicBoolean allItemsLoaded = new AtomicBoolean(false);
|
||||
private HashSet<String> itemsLoaded = new HashSet<>();
|
||||
private final AtomicInteger requestLoadedAtomic = new AtomicInteger();
|
||||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private Disposable subscriptionObserver;
|
||||
private Subscription feedSubscriber;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Fragment LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
subscriptionService = SubscriptionService.getInstance(activity);
|
||||
|
||||
FEED_LOAD_COUNT = howManyItemsToLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_feed, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
disposeEverything();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (wasLoading.get()) doInitialLoadLogic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
disposeEverything();
|
||||
subscriptionService = null;
|
||||
compositeDisposable = null;
|
||||
subscriptionObserver = null;
|
||||
feedSubscriber = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
// Do not monitor for updates when user is not viewing the feed fragment.
|
||||
// This is a waste of bandwidth.
|
||||
disposeEverything();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
/*@Override
|
||||
protected RecyclerView.LayoutManager getListLayoutManager() {
|
||||
boolean isPortrait = getResources().getDisplayMetrics().heightPixels > getResources().getDisplayMetrics().widthPixels;
|
||||
return new GridLayoutManager(activity, isPortrait ? 1 : 2);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setTitle(R.string.fragment_whats_new);
|
||||
}
|
||||
|
||||
if(useAsFrontPage) {
|
||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||
//supportActionBar.setDisplayShowTitleEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadContent() {
|
||||
resetFragment();
|
||||
super.reloadContent();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// StateSaving
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void writeTo(Queue<Object> objectsToSave) {
|
||||
super.writeTo(objectsToSave);
|
||||
objectsToSave.add(allItemsLoaded);
|
||||
objectsToSave.add(itemsLoaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
||||
super.readFrom(savedObjects);
|
||||
allItemsLoaded = (AtomicBoolean) savedObjects.poll();
|
||||
itemsLoaded = (HashSet<String>) savedObjects.poll();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Feed Loader
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void startLoading(boolean forceLoad) {
|
||||
if (DEBUG) Log.d(TAG, "startLoading() called with: forceLoad = [" + forceLoad + "]");
|
||||
if (subscriptionObserver != null) subscriptionObserver.dispose();
|
||||
|
||||
if (allItemsLoaded.get()) {
|
||||
if (infoListAdapter.getItemsList().size() == 0) {
|
||||
showEmptyState();
|
||||
} else {
|
||||
showListFooter(false);
|
||||
hideLoading();
|
||||
}
|
||||
|
||||
isLoading.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.set(true);
|
||||
showLoading();
|
||||
showListFooter(true);
|
||||
subscriptionObserver = subscriptionService.getSubscription()
|
||||
.onErrorReturnItem(Collections.<SubscriptionEntity>emptyList())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<List<SubscriptionEntity>>() {
|
||||
@Override
|
||||
public void accept(List<SubscriptionEntity> subscriptionEntities) throws Exception {
|
||||
handleResult(subscriptionEntities);
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
onError(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(@android.support.annotation.NonNull List<SubscriptionEntity> result) {
|
||||
super.handleResult(result);
|
||||
|
||||
if (result.isEmpty()) {
|
||||
infoListAdapter.clearStreamItemList();
|
||||
showEmptyState();
|
||||
return;
|
||||
}
|
||||
|
||||
subscriptionPoolSize = result.size();
|
||||
Flowable.fromIterable(result)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(getSubscriptionObserver());
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for reacting to user pulling request and starting a request for new feed stream.
|
||||
* <p>
|
||||
* On initialization, it automatically requests the amount of feed needed to display
|
||||
* a minimum amount required (FEED_LOAD_SIZE).
|
||||
* <p>
|
||||
* Upon receiving a user pull, it creates a Single Observer to fetch the ChannelInfo
|
||||
* containing the feed streams.
|
||||
**/
|
||||
private Subscriber<SubscriptionEntity> getSubscriptionObserver() {
|
||||
return new Subscriber<SubscriptionEntity>() {
|
||||
@Override
|
||||
public void onSubscribe(Subscription s) {
|
||||
if (feedSubscriber != null) feedSubscriber.cancel();
|
||||
feedSubscriber = s;
|
||||
|
||||
int requestSize = FEED_LOAD_COUNT - infoListAdapter.getItemsList().size();
|
||||
if (wasLoading.getAndSet(false)) requestSize = FEED_LOAD_COUNT;
|
||||
|
||||
boolean hasToLoad = requestSize > 0;
|
||||
if (hasToLoad) {
|
||||
requestLoadedAtomic.set(infoListAdapter.getItemsList().size());
|
||||
requestFeed(requestSize);
|
||||
}
|
||||
isLoading.set(hasToLoad);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(SubscriptionEntity subscriptionEntity) {
|
||||
if (!itemsLoaded.contains(subscriptionEntity.getServiceId() + subscriptionEntity.getUrl())) {
|
||||
subscriptionService.getChannelInfo(subscriptionEntity)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.onErrorComplete(new Predicate<Throwable>() {
|
||||
@Override
|
||||
public boolean test(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
|
||||
return FeedFragment.super.onError(throwable);
|
||||
}
|
||||
})
|
||||
.subscribe(getChannelInfoObserver(subscriptionEntity.getServiceId(), subscriptionEntity.getUrl()));
|
||||
} else {
|
||||
requestFeed(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable exception) {
|
||||
FeedFragment.this.onError(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
if (DEBUG) Log.d(TAG, "getSubscriptionObserver > onComplete() called");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* On each request, a subscription item from the updated table is transformed
|
||||
* into a ChannelInfo, containing the latest streams from the channel.
|
||||
* <p>
|
||||
* Currently, the feed uses the first into from the list of streams.
|
||||
* <p>
|
||||
* If chosen feed already displayed, then we request another feed from another
|
||||
* subscription, until the subscription table runs out of new items.
|
||||
* <p>
|
||||
* This Observer is self-contained and will dispose itself when complete. However, this
|
||||
* does not obey the fragment lifecycle and may continue running in the background
|
||||
* until it is complete. This is done due to RxJava2 no longer propagate errors once
|
||||
* an observer is unsubscribed while the thread process is still running.
|
||||
* <p>
|
||||
* To solve the above issue, we can either set a global RxJava Error Handler, or
|
||||
* manage exceptions case by case. This should be done if the current implementation is
|
||||
* too costly when dealing with larger subscription sets.
|
||||
*
|
||||
* @param url + serviceId to put in {@link #allItemsLoaded} to signal that this specific entity has been loaded.
|
||||
*/
|
||||
private MaybeObserver<ChannelInfo> getChannelInfoObserver(final int serviceId, final String url) {
|
||||
return new MaybeObserver<ChannelInfo>() {
|
||||
private Disposable observer;
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
observer = d;
|
||||
compositeDisposable.add(d);
|
||||
isLoading.set(true);
|
||||
}
|
||||
|
||||
// Called only when response is non-empty
|
||||
@Override
|
||||
public void onSuccess(final ChannelInfo channelInfo) {
|
||||
if (infoListAdapter == null || channelInfo.getRelatedItems().isEmpty()) {
|
||||
onDone();
|
||||
return;
|
||||
}
|
||||
|
||||
final InfoItem item = channelInfo.getRelatedItems().get(0);
|
||||
// Keep requesting new items if the current one already exists
|
||||
boolean itemExists = doesItemExist(infoListAdapter.getItemsList(), item);
|
||||
if (!itemExists) {
|
||||
infoListAdapter.addInfoItem(item);
|
||||
//updateSubscription(channelInfo);
|
||||
} else {
|
||||
requestFeed(1);
|
||||
}
|
||||
onDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable exception) {
|
||||
showSnackBarError(exception, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(serviceId), url, 0);
|
||||
requestFeed(1);
|
||||
onDone();
|
||||
}
|
||||
|
||||
// Called only when response is empty
|
||||
@Override
|
||||
public void onComplete() {
|
||||
onDone();
|
||||
}
|
||||
|
||||
private void onDone() {
|
||||
if (observer.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
itemsLoaded.add(serviceId + url);
|
||||
compositeDisposable.remove(observer);
|
||||
|
||||
int loaded = requestLoadedAtomic.incrementAndGet();
|
||||
if (loaded >= Math.min(FEED_LOAD_COUNT, subscriptionPoolSize)) {
|
||||
requestLoadedAtomic.set(0);
|
||||
isLoading.set(false);
|
||||
}
|
||||
|
||||
if (itemsLoaded.size() == subscriptionPoolSize) {
|
||||
if (DEBUG) Log.d(TAG, "getChannelInfoObserver > All Items Loaded");
|
||||
allItemsLoaded.set(true);
|
||||
showListFooter(false);
|
||||
isLoading.set(false);
|
||||
hideLoading();
|
||||
if (infoListAdapter.getItemsList().size() == 0) {
|
||||
showEmptyState();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadMoreItems() {
|
||||
isLoading.set(true);
|
||||
delayHandler.removeCallbacksAndMessages(null);
|
||||
// Add a little of a delay when requesting more items because the cache is so fast,
|
||||
// that the view seems stuck to the user when he scroll to the bottom
|
||||
delayHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestFeed(FEED_LOAD_COUNT);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasMoreItems() {
|
||||
return !allItemsLoaded.get();
|
||||
}
|
||||
|
||||
private final Handler delayHandler = new Handler();
|
||||
|
||||
private void requestFeed(final int count) {
|
||||
if (DEBUG) Log.d(TAG, "requestFeed() called with: count = [" + count + "], feedSubscriber = [" + feedSubscriber + "]");
|
||||
if (feedSubscriber == null) return;
|
||||
|
||||
isLoading.set(true);
|
||||
delayHandler.removeCallbacksAndMessages(null);
|
||||
feedSubscriber.request(count);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void resetFragment() {
|
||||
if (DEBUG) Log.d(TAG, "resetFragment() called");
|
||||
if (subscriptionObserver != null) subscriptionObserver.dispose();
|
||||
if (compositeDisposable != null) compositeDisposable.clear();
|
||||
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
|
||||
|
||||
delayHandler.removeCallbacksAndMessages(null);
|
||||
requestLoadedAtomic.set(0);
|
||||
allItemsLoaded.set(false);
|
||||
showListFooter(false);
|
||||
itemsLoaded.clear();
|
||||
}
|
||||
|
||||
private void disposeEverything() {
|
||||
if (subscriptionObserver != null) subscriptionObserver.dispose();
|
||||
if (compositeDisposable != null) compositeDisposable.clear();
|
||||
if (feedSubscriber != null) feedSubscriber.cancel();
|
||||
delayHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private boolean doesItemExist(final List<InfoItem> items, final InfoItem item) {
|
||||
for (final InfoItem existingItem : items) {
|
||||
if (existingItem.getInfoType() == item.getInfoType() &&
|
||||
existingItem.getServiceId() == item.getServiceId() &&
|
||||
existingItem.getName().equals(item.getName()) &&
|
||||
existingItem.getUrl().equals(item.getUrl())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int howManyItemsToLoad() {
|
||||
int heightPixels = getResources().getDisplayMetrics().heightPixels;
|
||||
int itemHeightPixels = activity.getResources().getDimensionPixelSize(R.dimen.video_item_search_height);
|
||||
|
||||
int items = itemHeightPixels > 0 ? heightPixels / itemHeightPixels + OFF_SCREEN_ITEMS_COUNT : MIN_ITEMS_INITIAL_LOAD;
|
||||
return Math.max(MIN_ITEMS_INITIAL_LOAD, items);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Fragment Error Handling
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void showError(String message, boolean showRetryButton) {
|
||||
resetFragment();
|
||||
super.showError(message, showRetryButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onError(Throwable exception) {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Requesting feed", errorId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.subscription;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import icepick.Icepick;
|
||||
import icepick.State;
|
||||
|
||||
public class ImportConfirmationDialog extends DialogFragment {
|
||||
@State
|
||||
protected Intent resultServiceIntent;
|
||||
|
||||
public void setResultServiceIntent(Intent resultServiceIntent) {
|
||||
this.resultServiceIntent = resultServiceIntent;
|
||||
}
|
||||
|
||||
public static void show(@NonNull Fragment fragment, @NonNull Intent resultServiceIntent) {
|
||||
if (fragment.getFragmentManager() == null) return;
|
||||
|
||||
final ImportConfirmationDialog confirmationDialog = new ImportConfirmationDialog();
|
||||
confirmationDialog.setResultServiceIntent(resultServiceIntent);
|
||||
confirmationDialog.show(fragment.getFragmentManager(), null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getContext(), ThemeHelper.getDialogTheme(getContext()))
|
||||
.setMessage(R.string.import_network_expensive_warning)
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
|
||||
if (resultServiceIntent != null && getContext() != null) {
|
||||
getContext().startService(resultServiceIntent);
|
||||
}
|
||||
dismiss();
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (resultServiceIntent == null) throw new IllegalStateException("Result intent is null");
|
||||
|
||||
Icepick.restoreInstanceState(this, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
Icepick.saveInstanceState(this, outState);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.subscription;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.subscription.SubscriptionService;
|
||||
import org.schabi.newpipe.subscription.services.SubscriptionsExportService;
|
||||
import org.schabi.newpipe.subscription.services.SubscriptionsImportService;
|
||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
import org.schabi.newpipe.views.CollapsibleView;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
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.subscription.services.SubscriptionsImportService.KEY_MODE;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_VALUE;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEntity>> {
|
||||
private static final int REQUEST_EXPORT_CODE = 666;
|
||||
private static final int REQUEST_IMPORT_CODE = 667;
|
||||
|
||||
private RecyclerView itemsList;
|
||||
@State
|
||||
protected Parcelable itemsListState;
|
||||
private InfoListAdapter infoListAdapter;
|
||||
|
||||
private View headerRootLayout;
|
||||
private View whatsNewItemListHeader;
|
||||
private View importExportListHeader;
|
||||
|
||||
@State
|
||||
protected Parcelable importExportOptionsState;
|
||||
private CollapsibleView importExportOptions;
|
||||
|
||||
private CompositeDisposable disposables = new CompositeDisposable();
|
||||
private SubscriptionService subscriptionService;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Fragment LifeCycle
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if (activity != null && isVisibleToUser) {
|
||||
setTitle(activity.getString(R.string.tab_subscriptions));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
infoListAdapter = new InfoListAdapter(activity);
|
||||
subscriptionService = SubscriptionService.getInstance(activity);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_subscription, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setupBroadcastReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
||||
importExportOptionsState = importExportOptions.onSaveInstanceState();
|
||||
|
||||
if (subscriptionBroadcastReceiver != null && activity != null) {
|
||||
LocalBroadcastManager.getInstance(activity).unregisterReceiver(subscriptionBroadcastReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (disposables != null) disposables.clear();
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (disposables != null) disposables.dispose();
|
||||
disposables = null;
|
||||
subscriptionService = null;
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/*/////////////////////////////////////////////////////////////////////////
|
||||
// Menu
|
||||
/////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||
setTitle(getString(R.string.tab_subscriptions));
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Subscriptions import/export
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private BroadcastReceiver subscriptionBroadcastReceiver;
|
||||
|
||||
private void setupBroadcastReceiver() {
|
||||
if (activity == null) return;
|
||||
|
||||
if (subscriptionBroadcastReceiver != null) {
|
||||
LocalBroadcastManager.getInstance(activity).unregisterReceiver(subscriptionBroadcastReceiver);
|
||||
}
|
||||
|
||||
final IntentFilter filters = new IntentFilter();
|
||||
filters.addAction(SubscriptionsExportService.EXPORT_COMPLETE_ACTION);
|
||||
filters.addAction(SubscriptionsImportService.IMPORT_COMPLETE_ACTION);
|
||||
subscriptionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (importExportOptions != null) importExportOptions.collapse();
|
||||
}
|
||||
};
|
||||
|
||||
LocalBroadcastManager.getInstance(activity).registerReceiver(subscriptionBroadcastReceiver, filters);
|
||||
}
|
||||
|
||||
private View addItemView(final String title, @DrawableRes final int icon, ViewGroup container) {
|
||||
final View itemRoot = View.inflate(getContext(), R.layout.subscription_import_export_item, null);
|
||||
final TextView titleView = itemRoot.findViewById(android.R.id.text1);
|
||||
final ImageView iconView = itemRoot.findViewById(android.R.id.icon1);
|
||||
|
||||
titleView.setText(title);
|
||||
iconView.setImageResource(icon);
|
||||
|
||||
container.addView(itemRoot);
|
||||
return itemRoot;
|
||||
}
|
||||
|
||||
private void setupImportFromItems(final ViewGroup listHolder) {
|
||||
final View previousBackupItem = addItemView(getString(R.string.previous_export), ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_backup), listHolder);
|
||||
previousBackupItem.setOnClickListener(item -> onImportPreviousSelected());
|
||||
|
||||
final int iconColor = ThemeHelper.isLightThemeSelected(getContext()) ? Color.BLACK : Color.WHITE;
|
||||
final String[] services = getResources().getStringArray(R.array.service_list);
|
||||
for (String serviceName : services) {
|
||||
try {
|
||||
final StreamingService service = NewPipe.getService(serviceName);
|
||||
|
||||
final SubscriptionExtractor subscriptionExtractor = service.getSubscriptionExtractor();
|
||||
if (subscriptionExtractor == null) continue;
|
||||
|
||||
final List<SubscriptionExtractor.ContentSource> supportedSources = subscriptionExtractor.getSupportedSources();
|
||||
if (supportedSources.isEmpty()) continue;
|
||||
|
||||
final View itemView = addItemView(serviceName, ServiceHelper.getIcon(service.getServiceId()), listHolder);
|
||||
final ImageView iconView = itemView.findViewById(android.R.id.icon1);
|
||||
iconView.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
itemView.setOnClickListener(selectedItem -> onImportFromServiceSelected(service.getServiceId()));
|
||||
} catch (ExtractionException e) {
|
||||
throw new RuntimeException("Services array contains an entry that it's not a valid service name (" + serviceName + ")", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupExportToItems(final ViewGroup listHolder) {
|
||||
final View previousBackupItem = addItemView(getString(R.string.file), ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_save), listHolder);
|
||||
previousBackupItem.setOnClickListener(item -> onExportSelected());
|
||||
}
|
||||
|
||||
private void onImportFromServiceSelected(int serviceId) {
|
||||
if (getParentFragment() == null) return;
|
||||
NavigationHelper.openSubscriptionsImportFragment(getParentFragment().getFragmentManager(), serviceId);
|
||||
}
|
||||
|
||||
private void onImportPreviousSelected() {
|
||||
startActivityForResult(FilePickerActivityHelper.chooseSingleFile(activity), REQUEST_IMPORT_CODE);
|
||||
}
|
||||
|
||||
private void onExportSelected() {
|
||||
final String date = new SimpleDateFormat("yyyyMMddHHmm", Locale.ENGLISH).format(new Date());
|
||||
final String exportName = "newpipe_subscriptions_" + date + ".json";
|
||||
final File exportFile = new File(Environment.getExternalStorageDirectory(), exportName);
|
||||
|
||||
startActivityForResult(FilePickerActivityHelper.chooseFileToSave(activity, exportFile.getAbsolutePath()), REQUEST_EXPORT_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (data != null && data.getData() != null && resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == REQUEST_EXPORT_CODE) {
|
||||
final File exportFile = Utils.getFileForUri(data.getData());
|
||||
if (!exportFile.getParentFile().canWrite() || !exportFile.getParentFile().canRead()) {
|
||||
Toast.makeText(activity, R.string.invalid_directory, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
activity.startService(new Intent(activity, SubscriptionsExportService.class)
|
||||
.putExtra(SubscriptionsExportService.KEY_FILE_PATH, exportFile.getAbsolutePath()));
|
||||
}
|
||||
} else if (requestCode == REQUEST_IMPORT_CODE) {
|
||||
final String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
||||
ImportConfirmationDialog.show(this, new Intent(activity, SubscriptionsImportService.class)
|
||||
.putExtra(KEY_MODE, PREVIOUS_EXPORT_MODE)
|
||||
.putExtra(KEY_VALUE, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*/////////////////////////////////////////////////////////////////////////
|
||||
// Fragment Views
|
||||
/////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
|
||||
infoListAdapter = new InfoListAdapter(getActivity());
|
||||
itemsList = rootView.findViewById(R.id.items_list);
|
||||
itemsList.setLayoutManager(new LinearLayoutManager(activity));
|
||||
|
||||
infoListAdapter.setHeader(headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, itemsList, false));
|
||||
whatsNewItemListHeader = headerRootLayout.findViewById(R.id.whats_new);
|
||||
importExportListHeader = headerRootLayout.findViewById(R.id.import_export);
|
||||
importExportOptions = headerRootLayout.findViewById(R.id.import_export_options);
|
||||
|
||||
infoListAdapter.useMiniItemVariants(true);
|
||||
itemsList.setAdapter(infoListAdapter);
|
||||
|
||||
setupImportFromItems(headerRootLayout.findViewById(R.id.import_from_options));
|
||||
setupExportToItems(headerRootLayout.findViewById(R.id.export_to_options));
|
||||
|
||||
if (importExportOptionsState != null) {
|
||||
importExportOptions.onRestoreInstanceState(importExportOptionsState);
|
||||
importExportOptionsState = null;
|
||||
}
|
||||
|
||||
importExportOptions.addListener(getExpandIconSyncListener(headerRootLayout.findViewById(R.id.import_export_expand_icon)));
|
||||
importExportOptions.ready();
|
||||
}
|
||||
|
||||
private CollapsibleView.StateListener getExpandIconSyncListener(final ImageView iconView) {
|
||||
return newState -> animateRotation(iconView, 250, newState == CollapsibleView.COLLAPSED ? 0 : 180);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initListeners() {
|
||||
super.initListeners();
|
||||
|
||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||
@Override
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
});
|
||||
|
||||
//noinspection ConstantConditions
|
||||
whatsNewItemListHeader.setOnClickListener(v ->
|
||||
NavigationHelper.openWhatsNewFragment(getParentFragment().getFragmentManager()));
|
||||
importExportListHeader.setOnClickListener(v -> importExportOptions.switchState());
|
||||
}
|
||||
|
||||
private void resetFragment() {
|
||||
if (disposables != null) disposables.clear();
|
||||
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Subscriptions Loader
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void startLoading(boolean forceLoad) {
|
||||
super.startLoading(forceLoad);
|
||||
resetFragment();
|
||||
|
||||
subscriptionService.getSubscription().toObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(getSubscriptionObserver());
|
||||
}
|
||||
|
||||
private Observer<List<SubscriptionEntity>> getSubscriptionObserver() {
|
||||
return new Observer<List<SubscriptionEntity>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
showLoading();
|
||||
disposables.add(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(List<SubscriptionEntity> subscriptions) {
|
||||
handleResult(subscriptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable exception) {
|
||||
SubscriptionFragment.this.onError(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(@NonNull List<SubscriptionEntity> result) {
|
||||
super.handleResult(result);
|
||||
|
||||
infoListAdapter.clearStreamItemList();
|
||||
|
||||
if (result.isEmpty()) {
|
||||
whatsNewItemListHeader.setVisibility(View.GONE);
|
||||
showEmptyState();
|
||||
} else {
|
||||
infoListAdapter.addInfoItemList(getSubscriptionItems(result));
|
||||
if (itemsListState != null) {
|
||||
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
||||
itemsListState = null;
|
||||
}
|
||||
whatsNewItemListHeader.setVisibility(View.VISIBLE);
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<InfoItem> getSubscriptionItems(List<SubscriptionEntity> subscriptions) {
|
||||
List<InfoItem> items = new ArrayList<>();
|
||||
for (final SubscriptionEntity subscription : subscriptions) items.add(subscription.toChannelInfoItem());
|
||||
|
||||
Collections.sort(items,
|
||||
(InfoItem o1, InfoItem o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
|
||||
return items;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Contract
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void showLoading() {
|
||||
super.showLoading();
|
||||
animateView(itemsList, false, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideLoading() {
|
||||
super.hideLoading();
|
||||
animateView(itemsList, true, 200);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Fragment Error Handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected boolean onError(Throwable exception) {
|
||||
resetFragment();
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Subscriptions", R.string.general_error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.subscription;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.text.util.LinkifyCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import org.schabi.newpipe.BaseFragment;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.subscription.services.SubscriptionsImportService;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import icepick.State;
|
||||
|
||||
import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.INPUT_STREAM_MODE;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_MODE;
|
||||
import static org.schabi.newpipe.subscription.services.SubscriptionsImportService.KEY_VALUE;
|
||||
|
||||
public class SubscriptionsImportFragment extends BaseFragment {
|
||||
private static final int REQUEST_IMPORT_FILE_CODE = 666;
|
||||
|
||||
@State
|
||||
protected int currentServiceId = Constants.NO_SERVICE_ID;
|
||||
|
||||
private List<SubscriptionExtractor.ContentSource> supportedSources;
|
||||
private String relatedUrl;
|
||||
@StringRes
|
||||
private int instructionsString;
|
||||
|
||||
public static SubscriptionsImportFragment getInstance(int serviceId) {
|
||||
SubscriptionsImportFragment instance = new SubscriptionsImportFragment();
|
||||
instance.setInitialData(serviceId);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInitialData(int serviceId) {
|
||||
this.currentServiceId = serviceId;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private TextView infoTextView;
|
||||
|
||||
private EditText inputText;
|
||||
private Button inputButton;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Fragment LifeCycle
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setupServiceVariables();
|
||||
if (supportedSources.isEmpty() && currentServiceId != Constants.NO_SERVICE_ID) {
|
||||
ErrorActivity.reportError(activity, Collections.emptyList(), null, null, ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE,
|
||||
NewPipe.getNameOfService(currentServiceId), "Service don't support importing", R.string.general_error));
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if (isVisibleToUser) {
|
||||
setTitle(getString(R.string.import_title));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_import, container, false);
|
||||
}
|
||||
|
||||
/*/////////////////////////////////////////////////////////////////////////
|
||||
// Fragment Views
|
||||
/////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
|
||||
inputButton = rootView.findViewById(R.id.input_button);
|
||||
inputText = rootView.findViewById(R.id.input_text);
|
||||
|
||||
infoTextView = rootView.findViewById(R.id.info_text_view);
|
||||
|
||||
// TODO: Support services that can import from more than one source (show the option to the user)
|
||||
if (supportedSources.contains(CHANNEL_URL)) {
|
||||
inputButton.setText(R.string.import_title);
|
||||
inputText.setVisibility(View.VISIBLE);
|
||||
inputText.setHint(ServiceHelper.getImportInstructionsHint(currentServiceId));
|
||||
} else {
|
||||
inputButton.setText(R.string.import_file_title);
|
||||
}
|
||||
|
||||
if (instructionsString != 0) {
|
||||
if (TextUtils.isEmpty(relatedUrl)) {
|
||||
setInfoText(getString(instructionsString));
|
||||
} else {
|
||||
setInfoText(getString(instructionsString, relatedUrl));
|
||||
}
|
||||
} else {
|
||||
setInfoText("");
|
||||
}
|
||||
|
||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||
setTitle(getString(R.string.import_title));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initListeners() {
|
||||
super.initListeners();
|
||||
inputButton.setOnClickListener(v -> onImportClicked());
|
||||
}
|
||||
|
||||
private void onImportClicked() {
|
||||
if (inputText.getVisibility() == View.VISIBLE) {
|
||||
final String value = inputText.getText().toString();
|
||||
if (!value.isEmpty()) onImportUrl(value);
|
||||
} else {
|
||||
onImportFile();
|
||||
}
|
||||
}
|
||||
|
||||
public void onImportUrl(String value) {
|
||||
ImportConfirmationDialog.show(this, new Intent(activity, SubscriptionsImportService.class)
|
||||
.putExtra(KEY_MODE, CHANNEL_URL_MODE)
|
||||
.putExtra(KEY_VALUE, value)
|
||||
.putExtra(Constants.KEY_SERVICE_ID, currentServiceId));
|
||||
}
|
||||
|
||||
public void onImportFile() {
|
||||
startActivityForResult(FilePickerActivityHelper.chooseSingleFile(activity), REQUEST_IMPORT_FILE_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (data == null) return;
|
||||
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMPORT_FILE_CODE && data.getData() != null) {
|
||||
final String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
||||
ImportConfirmationDialog.show(this, new Intent(activity, SubscriptionsImportService.class)
|
||||
.putExtra(KEY_MODE, INPUT_STREAM_MODE)
|
||||
.putExtra(KEY_VALUE, path)
|
||||
.putExtra(Constants.KEY_SERVICE_ID, currentServiceId));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Subscriptions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void setupServiceVariables() {
|
||||
if (currentServiceId != Constants.NO_SERVICE_ID) {
|
||||
try {
|
||||
final SubscriptionExtractor extractor = NewPipe.getService(currentServiceId).getSubscriptionExtractor();
|
||||
supportedSources = extractor.getSupportedSources();
|
||||
relatedUrl = extractor.getRelatedUrl();
|
||||
instructionsString = ServiceHelper.getImportInstructions(currentServiceId);
|
||||
return;
|
||||
} catch (ExtractionException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
supportedSources = Collections.emptyList();
|
||||
relatedUrl = null;
|
||||
instructionsString = 0;
|
||||
}
|
||||
|
||||
private void setInfoText(String infoString) {
|
||||
infoTextView.setText(infoString);
|
||||
LinkifyCompat.addLinks(infoTextView, Linkify.WEB_URLS);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue