2017-09-03 08:04:18 +02:00
|
|
|
package org.schabi.newpipe.fragments.list;
|
|
|
|
|
|
|
|
import android.os.Bundle;
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.annotation.NonNull;
|
2017-09-03 08:04:18 +02:00
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.View;
|
|
|
|
|
|
|
|
import org.schabi.newpipe.extractor.ListExtractor;
|
|
|
|
import org.schabi.newpipe.extractor.ListInfo;
|
2017-10-08 21:04:37 +02:00
|
|
|
import org.schabi.newpipe.util.Constants;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
import java.util.Queue;
|
|
|
|
|
|
|
|
import icepick.State;
|
|
|
|
import io.reactivex.Single;
|
|
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
|
|
import io.reactivex.disposables.Disposable;
|
|
|
|
import io.reactivex.schedulers.Schedulers;
|
|
|
|
|
2018-02-24 22:57:25 +01:00
|
|
|
public abstract class BaseListInfoFragment<I extends ListInfo>
|
2018-03-18 16:37:49 +01:00
|
|
|
extends BaseListFragment<I, ListExtractor.InfoItemsPage> {
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
@State
|
2017-10-08 21:04:37 +02:00
|
|
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
2017-09-03 08:04:18 +02:00
|
|
|
@State
|
|
|
|
protected String name;
|
|
|
|
@State
|
2018-07-10 16:26:42 +02:00
|
|
|
protected String url;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
protected I currentInfo;
|
2018-02-24 22:57:25 +01:00
|
|
|
protected String currentNextPageUrl;
|
2017-09-03 08:04:18 +02:00
|
|
|
protected Disposable currentWorker;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
|
|
|
super.initViews(rootView, savedInstanceState);
|
|
|
|
setTitle(name);
|
|
|
|
showListFooter(hasMoreItems());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
// Check if it was loading when the fragment was stopped/paused,
|
|
|
|
if (wasLoading.getAndSet(false)) {
|
|
|
|
if (hasMoreItems() && infoListAdapter.getItemsList().size() > 0) {
|
|
|
|
loadMoreItems();
|
|
|
|
} else {
|
|
|
|
doInitialLoadLogic();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
currentWorker = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// State Saving
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void writeTo(Queue<Object> objectsToSave) {
|
|
|
|
super.writeTo(objectsToSave);
|
|
|
|
objectsToSave.add(currentInfo);
|
2018-02-24 22:57:25 +01:00
|
|
|
objectsToSave.add(currentNextPageUrl);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
|
|
|
super.readFrom(savedObjects);
|
|
|
|
currentInfo = (I) savedObjects.poll();
|
2018-02-24 22:57:25 +01:00
|
|
|
currentNextPageUrl = (String) savedObjects.poll();
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Load and handle
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
protected void doInitialLoadLogic() {
|
|
|
|
if (DEBUG) Log.d(TAG, "doInitialLoadLogic() called");
|
|
|
|
if (currentInfo == null) {
|
|
|
|
startLoading(false);
|
|
|
|
} else handleResult(currentInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implement the logic to load the info from the network.<br/>
|
|
|
|
* You can use the default implementations from {@link org.schabi.newpipe.util.ExtractorHelper}.
|
|
|
|
*
|
|
|
|
* @param forceLoad allow or disallow the result to come from the cache
|
|
|
|
*/
|
|
|
|
protected abstract Single<I> loadResult(boolean forceLoad);
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void startLoading(boolean forceLoad) {
|
|
|
|
super.startLoading(forceLoad);
|
|
|
|
|
|
|
|
showListFooter(false);
|
|
|
|
currentInfo = null;
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
currentWorker = loadResult(forceLoad)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-01-20 15:24:45 +01:00
|
|
|
.subscribe((@NonNull I result) -> {
|
|
|
|
isLoading.set(false);
|
|
|
|
currentInfo = result;
|
2018-03-18 16:37:49 +01:00
|
|
|
currentNextPageUrl = result.getNextPageUrl();
|
2018-01-20 15:24:45 +01:00
|
|
|
handleResult(result);
|
|
|
|
}, (@NonNull Throwable throwable) -> onError(throwable));
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implement the logic to load more items<br/>
|
|
|
|
* You can use the default implementations from {@link org.schabi.newpipe.util.ExtractorHelper}
|
|
|
|
*/
|
2018-03-18 16:37:49 +01:00
|
|
|
protected abstract Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic();
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
protected void loadMoreItems() {
|
|
|
|
isLoading.set(true);
|
|
|
|
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
currentWorker = loadMoreItemsLogic()
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-03-18 16:37:49 +01:00
|
|
|
.subscribe((@io.reactivex.annotations.NonNull ListExtractor.InfoItemsPage InfoItemsPage) -> {
|
2018-01-20 15:24:45 +01:00
|
|
|
isLoading.set(false);
|
2018-03-18 16:37:49 +01:00
|
|
|
handleNextItems(InfoItemsPage);
|
2018-01-20 15:24:45 +01:00
|
|
|
}, (@io.reactivex.annotations.NonNull Throwable throwable) -> {
|
|
|
|
isLoading.set(false);
|
|
|
|
onError(throwable);
|
2017-09-03 08:04:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-03-18 16:37:49 +01:00
|
|
|
public void handleNextItems(ListExtractor.InfoItemsPage result) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.handleNextItems(result);
|
2018-03-18 16:37:49 +01:00
|
|
|
currentNextPageUrl = result.getNextPageUrl();
|
|
|
|
infoListAdapter.addInfoItemList(result.getItems());
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
showListFooter(hasMoreItems());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean hasMoreItems() {
|
2018-02-24 22:57:25 +01:00
|
|
|
return !TextUtils.isEmpty(currentNextPageUrl);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Contract
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void handleResult(@NonNull I result) {
|
|
|
|
super.handleResult(result);
|
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
name = result.getName();
|
2017-09-03 08:04:18 +02:00
|
|
|
setTitle(name);
|
|
|
|
|
|
|
|
if (infoListAdapter.getItemsList().size() == 0) {
|
2018-03-18 16:37:49 +01:00
|
|
|
if (result.getRelatedItems().size() > 0) {
|
|
|
|
infoListAdapter.addInfoItemList(result.getRelatedItems());
|
2017-09-03 08:04:18 +02:00
|
|
|
showListFooter(hasMoreItems());
|
|
|
|
} else {
|
|
|
|
infoListAdapter.clearStreamItemList();
|
|
|
|
showEmptyState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2018-07-10 16:26:42 +02:00
|
|
|
protected void setInitialData(int serviceId, String url, String name) {
|
2017-09-03 08:04:18 +02:00
|
|
|
this.serviceId = serviceId;
|
2018-07-10 16:26:42 +02:00
|
|
|
this.url = url;
|
2017-09-03 08:04:18 +02:00
|
|
|
this.name = !TextUtils.isEmpty(name) ? name : "";
|
|
|
|
}
|
|
|
|
}
|