mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 02:39:23 +02:00
Partially loaded catalogs
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1607 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
0566a317cc
commit
d0230f72cb
14 changed files with 219 additions and 68 deletions
|
@ -8,8 +8,8 @@ DONE сделать SeekBar (как в ветке alex) в пункте Navigate
|
|||
** синхронизация ресурсов (последняя - 1604)
|
||||
** Записать изменения в ChangeLog
|
||||
|
||||
* каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен:
|
||||
в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг)
|
||||
DONE каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен:
|
||||
в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг)
|
||||
* 3 иконки в верхнем-правом углу для книжек
|
||||
|
||||
DONE регистрация новых пользователей -- в диалоге authentication
|
||||
|
|
|
@ -30,8 +30,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
|
||||
private final ItemsLoadingHandler myHandler;
|
||||
|
||||
private final long myUpdateInterval; // in milliseconds
|
||||
private final int myItemsLimit;
|
||||
public final long UpdateInterval; // in milliseconds
|
||||
public final int ItemsLimit;
|
||||
|
||||
private boolean myInterruptRequested;
|
||||
private boolean myInterruptConfirmed;
|
||||
|
@ -42,13 +42,13 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
private Object myFinishedLock = new Object();
|
||||
|
||||
|
||||
public void interrupt() {
|
||||
public void interruptLoading() {
|
||||
synchronized (myInterruptLock) {
|
||||
myInterruptRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean confirmInterrupt() {
|
||||
private boolean confirmInterruptLoading() {
|
||||
synchronized (myInterruptLock) {
|
||||
if (myInterruptRequested) {
|
||||
myInterruptConfirmed = true;
|
||||
|
@ -57,7 +57,7 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean tryResume() {
|
||||
public boolean tryResumeLoading() {
|
||||
synchronized (myInterruptLock) {
|
||||
if (!myInterruptConfirmed) {
|
||||
myInterruptRequested = false;
|
||||
|
@ -66,12 +66,18 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isInterrupted() {
|
||||
private boolean isLoadingInterrupted() {
|
||||
synchronized (myInterruptLock) {
|
||||
return myInterruptConfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLoadingInterruptRequested() {
|
||||
synchronized (myInterruptLock) {
|
||||
return myInterruptRequested;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ItemsLoadingRunnable(ItemsLoadingHandler handler) {
|
||||
this(handler, 1000, 500);
|
||||
|
@ -79,8 +85,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
|
||||
public ItemsLoadingRunnable(ItemsLoadingHandler handler, long updateIntervalMillis, int itemsLimit) {
|
||||
myHandler = handler;
|
||||
myUpdateInterval = updateIntervalMillis;
|
||||
myItemsLimit = itemsLimit;
|
||||
UpdateInterval = updateIntervalMillis;
|
||||
ItemsLimit = itemsLimit;
|
||||
}
|
||||
|
||||
public abstract String doBefore();
|
||||
|
@ -98,24 +104,29 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
err = doLoading(new NetworkOperationData.OnNewItemListener() {
|
||||
private long myUpdateTime;
|
||||
private int myItemsNumber;
|
||||
public boolean onNewItem(NetworkLibraryItem item) {
|
||||
public void onNewItem(NetworkLibraryItem item) {
|
||||
myHandler.addItem(item);
|
||||
final boolean interrupted = confirmInterrupt();
|
||||
if (interrupted || myItemsNumber++ >= myItemsLimit) {
|
||||
return true;
|
||||
}
|
||||
++myItemsNumber;
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now > myUpdateTime) {
|
||||
myHandler.sendUpdateItems();
|
||||
myUpdateTime = now + myUpdateInterval;
|
||||
myUpdateTime = now + UpdateInterval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean requestInterrupt() {
|
||||
return isLoadingInterruptRequested() || myItemsNumber >= ItemsLimit;
|
||||
}
|
||||
public boolean confirmInterrupt() {
|
||||
return confirmInterruptLoading() || myItemsNumber >= ItemsLimit;
|
||||
}
|
||||
});
|
||||
myHandler.sendUpdateItems();
|
||||
myHandler.ensureItemsProcessed();
|
||||
myHandler.sendFinish(err, isInterrupted());
|
||||
myHandler.sendFinish(err, isLoadingInterrupted());
|
||||
myHandler.ensureFinishProcessed();
|
||||
}
|
||||
|
||||
void runFinishHandler() {
|
||||
synchronized (myFinishedLock) {
|
||||
if (myFinishedHandler != null) {
|
||||
myFinishedHandler.sendEmptyMessage(0);
|
||||
|
@ -124,6 +135,7 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void runOnFinish(final Runnable runnable) {
|
||||
if (myFinishedHandler != null) {
|
||||
return;
|
||||
|
|
|
@ -288,7 +288,8 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
|
||||
public void onFinish(String errorMessage, boolean interrupted) {
|
||||
if (interrupted) {
|
||||
if (interrupted &&
|
||||
(!myTree.Item.supportsResumeLoading() || errorMessage != null)) {
|
||||
myTree.ChildrenItems.clear();
|
||||
myTree.clear();
|
||||
} else {
|
||||
|
@ -336,11 +337,14 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
|
||||
private final NetworkCatalogTree myTree;
|
||||
private final boolean myCheckAuthentication;
|
||||
private final boolean myResumeNotLoad;
|
||||
|
||||
public ExpandCatalogRunnable(ItemsLoadingHandler handler, NetworkCatalogTree tree, boolean checkAuthentication) {
|
||||
public ExpandCatalogRunnable(ItemsLoadingHandler handler,
|
||||
NetworkCatalogTree tree, boolean checkAuthentication, boolean resumeNotLoad) {
|
||||
super(handler);
|
||||
myTree = tree;
|
||||
myCheckAuthentication = checkAuthentication;
|
||||
myResumeNotLoad = resumeNotLoad;
|
||||
}
|
||||
|
||||
public String getResourceKey() {
|
||||
|
@ -369,6 +373,9 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
|
||||
public String doLoading(NetworkOperationData.OnNewItemListener doWithListener) {
|
||||
if (myResumeNotLoad) {
|
||||
return myTree.Item.resumeLoading(doWithListener);
|
||||
}
|
||||
return myTree.Item.loadChildren(doWithListener);
|
||||
}
|
||||
}
|
||||
|
@ -380,10 +387,15 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
NetworkView.Instance().tryResumeLoading(activity, tree, url, new Runnable() {
|
||||
public void run() {
|
||||
boolean resumeNotLoad = false;
|
||||
if (tree.hasChildren()) {
|
||||
if (tree.isContentValid()) {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
return;
|
||||
if (tree.Item.supportsResumeLoading()) {
|
||||
resumeNotLoad = true;
|
||||
} else {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
tree.ChildrenItems.clear();
|
||||
tree.clear();
|
||||
|
@ -394,7 +406,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
new ExpandCatalogRunnable(handler, tree, true)
|
||||
new ExpandCatalogRunnable(handler, tree, true, resumeNotLoad)
|
||||
);
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
}
|
||||
|
@ -416,7 +428,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
new ExpandCatalogRunnable(handler, tree, false)
|
||||
new ExpandCatalogRunnable(handler, tree, false, false)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ public class NetworkCatalogActivity extends NetworkBaseActivity {
|
|||
if (key != null && NetworkView.Instance().isInitialized()) {
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(key);
|
||||
if (runnable != null) {
|
||||
runnable.interrupt();
|
||||
runnable.interruptLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,9 +153,12 @@ class NetworkView {
|
|||
}
|
||||
}
|
||||
|
||||
ItemsLoadingRunnable removeItemsLoadingRunnable(String key) {
|
||||
void removeItemsLoadingRunnable(String key) {
|
||||
synchronized (myItemsLoadingRunnables) {
|
||||
return myItemsLoadingRunnables.remove(key);
|
||||
ItemsLoadingRunnable runnable = myItemsLoadingRunnables.remove(key);
|
||||
if (runnable != null) {
|
||||
runnable.runFinishHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,8 +167,8 @@ class NetworkView {
|
|||
}
|
||||
|
||||
public void tryResumeLoading(NetworkBaseActivity activity, NetworkTree tree, String key, Runnable expandRunnable) {
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(key);
|
||||
if (runnable != null && runnable.tryResume()) {
|
||||
final ItemsLoadingRunnable runnable = getItemsLoadingRunnable(key);
|
||||
if (runnable != null && runnable.tryResumeLoading()) {
|
||||
openTree(activity, tree, key);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -73,4 +73,9 @@ public abstract class AbstractNetworkLink implements INetworkLink {
|
|||
public Set<String> getLinkKeys() {
|
||||
return myLinks.keySet();
|
||||
}
|
||||
|
||||
public NetworkOperationData createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener) {
|
||||
return new NetworkOperationData(link, listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ public interface INetworkLink {
|
|||
|
||||
Set<String> getLinkKeys();
|
||||
|
||||
NetworkOperationData createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener);
|
||||
|
||||
ZLNetworkRequest simpleSearchRequest(String pattern, NetworkOperationData data);
|
||||
ZLNetworkRequest resume(NetworkOperationData data);
|
||||
|
||||
|
|
|
@ -92,13 +92,14 @@ public abstract class NetworkCatalogItem extends NetworkLibraryItem {
|
|||
|
||||
public abstract String loadChildren(NetworkOperationData.OnNewItemListener listener); // returns Error Message
|
||||
|
||||
/*public final String loadChildren(final List<NetworkLibraryItem> children) {
|
||||
return loadChildren(new CatalogListener() {
|
||||
public void onNewItem(NetworkLibraryItem item) {
|
||||
children.add(item);
|
||||
}
|
||||
});
|
||||
}*/
|
||||
public boolean supportsResumeLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String resumeLoading(NetworkOperationData.OnNewItemListener listener) { // returns Error Message
|
||||
return NetworkErrors.errorMessage(NetworkErrors.ERROR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method is called each time this item is displayed to the user.
|
||||
|
|
|
@ -410,9 +410,15 @@ public class NetworkLibrary {
|
|||
LinkedList<ZLNetworkRequest> requestList = new LinkedList<ZLNetworkRequest>();
|
||||
LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>();
|
||||
|
||||
NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
|
||||
public synchronized boolean onNewItem(NetworkLibraryItem item) {
|
||||
return listener.onNewItem(item);
|
||||
final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
|
||||
public synchronized void onNewItem(NetworkLibraryItem item) {
|
||||
listener.onNewItem(item);
|
||||
}
|
||||
public synchronized boolean requestInterrupt() {
|
||||
return listener.requestInterrupt();
|
||||
}
|
||||
public synchronized boolean confirmInterrupt() {
|
||||
return listener.confirmInterrupt();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -421,8 +427,8 @@ public class NetworkLibrary {
|
|||
//if (link.OnOption.getValue()) {
|
||||
// execute next code only if link is enabled
|
||||
//}
|
||||
NetworkOperationData data = new NetworkOperationData(link, synchronizedListener);
|
||||
ZLNetworkRequest request = link.simpleSearchRequest(pattern, data);
|
||||
final NetworkOperationData data = link.createOperationData(link, synchronizedListener);
|
||||
final ZLNetworkRequest request = link.simpleSearchRequest(pattern, data);
|
||||
if (request != null) {
|
||||
dataList.add(data);
|
||||
requestList.add(request);
|
||||
|
|
|
@ -25,12 +25,15 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
|||
public class NetworkOperationData {
|
||||
|
||||
public interface OnNewItemListener {
|
||||
// return true to interrupt reading; return false to continue reading
|
||||
boolean onNewItem(NetworkLibraryItem item);
|
||||
void onNewItem(NetworkLibraryItem item);
|
||||
|
||||
// return true to confirm interrupt reading; return false to continue reading
|
||||
boolean requestInterrupt();
|
||||
boolean confirmInterrupt();
|
||||
}
|
||||
|
||||
public final INetworkLink Link;
|
||||
public final OnNewItemListener Listener;
|
||||
public OnNewItemListener Listener;
|
||||
public String ResumeURI;
|
||||
|
||||
private int myResumeCount;
|
||||
|
@ -48,6 +51,8 @@ public class NetworkOperationData {
|
|||
if (++myResumeCount >= 10) { // FIXME: hardcoded resume limit constant!!!
|
||||
return null;
|
||||
}
|
||||
return Link.resume(this);
|
||||
final ZLNetworkRequest request = Link.resume(this);
|
||||
clear();
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,14 @@ import org.geometerplus.fbreader.network.authentication.litres.LitResBookshelfIt
|
|||
class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||
|
||||
private final String myBaseURL;
|
||||
private final NetworkOperationData myData;
|
||||
private final OPDSCatalogItem.State myData;
|
||||
|
||||
private int myIndex;
|
||||
|
||||
private String myNextURL;
|
||||
private String mySkipUntilTitle;
|
||||
|
||||
private int myItemsToLoad = -1;
|
||||
|
||||
/**
|
||||
* Creates new OPDSFeedReader instance that can be used to get NetworkLibraryItem objects from OPDS feeds.
|
||||
|
@ -43,15 +47,17 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
|||
* @param result network results buffer. Must be created using OPDSLink corresponding to the OPDS feed,
|
||||
* that will be read using this instance of the reader.
|
||||
*/
|
||||
NetworkOPDSFeedReader(String baseURL, NetworkOperationData result) {
|
||||
NetworkOPDSFeedReader(String baseURL, OPDSCatalogItem.State result) {
|
||||
myBaseURL = baseURL;
|
||||
myData = result;
|
||||
mySkipUntilTitle = myData.LastLoadedTitle;
|
||||
if (!(result.Link instanceof OPDSLink)) {
|
||||
throw new IllegalArgumentException("Parameter `result` has invalid `Link` field value: result.Link must be an instance of OPDSLink class.");
|
||||
}
|
||||
}
|
||||
|
||||
public void processFeedStart() {
|
||||
myData.ResumeURI = myBaseURL;
|
||||
}
|
||||
|
||||
private static String filter(String value) {
|
||||
|
@ -64,6 +70,13 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
|||
public void processFeedMetadata(OPDSFeedMetadata feed, boolean beforeEntries) {
|
||||
if (beforeEntries) {
|
||||
myIndex = feed.OpensearchStartIndex - 1;
|
||||
if (feed.OpensearchItemsPerPage > 0) {
|
||||
myItemsToLoad = feed.OpensearchItemsPerPage;
|
||||
final int len = feed.OpensearchTotalResults - myIndex;
|
||||
if (len > 0 && len < myItemsToLoad) {
|
||||
myItemsToLoad = len;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
final OPDSLink opdsLink = (OPDSLink) myData.Link;
|
||||
|
@ -72,12 +85,20 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
|||
String type = link.getType();
|
||||
String rel = opdsLink.relation(filter(link.getRel()), type);
|
||||
if (type == OPDSConstants.MIME_APP_ATOM && rel == "next") {
|
||||
myData.ResumeURI = href;
|
||||
myNextURL = href;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processFeedEnd() {
|
||||
if (mySkipUntilTitle != null) {
|
||||
// Last loaded element was not found => resume error => DO NOT RESUME
|
||||
// TODO: notify user about error???
|
||||
// TODO: do reload???
|
||||
myNextURL = null;
|
||||
}
|
||||
myData.ResumeURI = myNextURL;
|
||||
myData.LastLoadedTitle = null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,10 +131,38 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean tryInterrupt() {
|
||||
if (myData.Listener.requestInterrupt()) {
|
||||
myData.Interrupt = true;
|
||||
|
||||
final int noninterruptableRemainder = 10;
|
||||
if (myItemsToLoad < 0 || myItemsToLoad > noninterruptableRemainder) {
|
||||
if (myData.Listener.confirmInterrupt()) {
|
||||
return true;
|
||||
} else {
|
||||
myData.Interrupt = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean processFeedEntry(OPDSEntry entry) {
|
||||
if (myItemsToLoad >= 0) {
|
||||
--myItemsToLoad;
|
||||
}
|
||||
|
||||
if (mySkipUntilTitle != null) {
|
||||
if (mySkipUntilTitle.equals(entry.Title)) {
|
||||
mySkipUntilTitle = null;
|
||||
}
|
||||
return tryInterrupt();
|
||||
}
|
||||
myData.LastLoadedTitle = entry.Title;
|
||||
|
||||
final OPDSLink opdsLink = (OPDSLink) myData.Link;
|
||||
if (opdsLink.getCondition(entry.Id.Uri) == OPDSLink.FeedCondition.NEVER) {
|
||||
return false;
|
||||
return tryInterrupt();
|
||||
}
|
||||
boolean hasBookLink = false;
|
||||
for (ATOMLink link: entry.Links) {
|
||||
|
@ -137,11 +186,9 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
|||
item = readCatalogItem(entry);
|
||||
}
|
||||
if (item != null) {
|
||||
//item.dbgEntry = entry;
|
||||
//myData.Items.add(item);
|
||||
return myData.Listener.onNewItem(item);
|
||||
myData.Listener.onNewItem(item);
|
||||
}
|
||||
return false;
|
||||
return tryInterrupt();
|
||||
}
|
||||
|
||||
private static final String AuthorPrefix = "author:";
|
||||
|
|
|
@ -29,6 +29,23 @@ import org.geometerplus.fbreader.network.*;
|
|||
|
||||
class OPDSCatalogItem extends NetworkCatalogItem {
|
||||
|
||||
static class State extends NetworkOperationData {
|
||||
|
||||
public String LastLoadedTitle;
|
||||
public boolean Interrupt;
|
||||
|
||||
public State(INetworkLink link, OnNewItemListener listener) {
|
||||
super(link, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
Interrupt = false;
|
||||
}
|
||||
}
|
||||
private State myLoadingState;
|
||||
|
||||
OPDSCatalogItem(INetworkLink link, String title, String summary, String cover, Map<Integer, String> urlByType) {
|
||||
super(link, title, summary, cover, urlByType);
|
||||
}
|
||||
|
@ -41,21 +58,54 @@ class OPDSCatalogItem extends NetworkCatalogItem {
|
|||
super(link, title, summary, cover, urlByType, visibility, catalogType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String loadChildren(NetworkOperationData.OnNewItemListener listener) {
|
||||
|
||||
final NetworkOperationData data = new NetworkOperationData(Link, listener);
|
||||
|
||||
ZLNetworkRequest networkRequest =
|
||||
((OPDSLink) Link).createNetworkData(URLByType.get(URL_CATALOG), data);
|
||||
|
||||
private String doLoadChildren(NetworkOperationData.OnNewItemListener listener,
|
||||
ZLNetworkRequest networkRequest) {
|
||||
while (networkRequest != null) {
|
||||
final String errorMessage = ZLNetworkManager.Instance().perform(networkRequest);
|
||||
if (errorMessage != null) {
|
||||
myLoadingState = null;
|
||||
return errorMessage;
|
||||
}
|
||||
networkRequest = data.resume();
|
||||
if (myLoadingState.Interrupt) {
|
||||
if (myLoadingState.LastLoadedTitle == null) {
|
||||
// In this case Catalog loading was not interrupted, and
|
||||
// we must confirm interruption here.
|
||||
if (listener.confirmInterrupt()) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
networkRequest = myLoadingState.resume();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String loadChildren(NetworkOperationData.OnNewItemListener listener) {
|
||||
OPDSLink opdsLink = (OPDSLink) Link;
|
||||
|
||||
myLoadingState = opdsLink.createOperationData(Link, listener);
|
||||
|
||||
ZLNetworkRequest networkRequest =
|
||||
opdsLink.createNetworkData(URLByType.get(URL_CATALOG), myLoadingState);
|
||||
|
||||
return doLoadChildren(listener, networkRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean supportsResumeLoading() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String resumeLoading(NetworkOperationData.OnNewItemListener listener) {
|
||||
if (myLoadingState == null) {
|
||||
return null;
|
||||
}
|
||||
myLoadingState.Listener = listener;
|
||||
ZLNetworkRequest networkRequest = myLoadingState.resume();
|
||||
return doLoadChildren(listener, networkRequest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ class OPDSLink extends AbstractNetworkLink {
|
|||
myAuthenticationManager = mgr;
|
||||
}
|
||||
|
||||
ZLNetworkRequest createNetworkData(String url, final NetworkOperationData result) {
|
||||
ZLNetworkRequest createNetworkData(String url, final OPDSCatalogItem.State result) {
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -97,20 +97,24 @@ class OPDSLink extends AbstractNetworkLink {
|
|||
return getLink(URL_SEARCH).replace("%s", query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OPDSCatalogItem.State createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener) {
|
||||
return new OPDSCatalogItem.State(link, listener);
|
||||
}
|
||||
|
||||
public ZLNetworkRequest simpleSearchRequest(String pattern, NetworkOperationData data) {
|
||||
if (getLink(URL_SEARCH) == null) {
|
||||
return null;
|
||||
}
|
||||
return createNetworkData(
|
||||
searchURL(ZLNetworkUtil.htmlEncode(pattern)),
|
||||
data
|
||||
(OPDSCatalogItem.State) data
|
||||
);
|
||||
}
|
||||
|
||||
public ZLNetworkRequest resume(NetworkOperationData data) {
|
||||
String url = data.ResumeURI;
|
||||
data.clear();
|
||||
return createNetworkData(url, data);
|
||||
return createNetworkData(data.ResumeURI, (OPDSCatalogItem.State) data);
|
||||
}
|
||||
|
||||
public NetworkLibraryItem libraryItem() {
|
||||
|
|
|
@ -173,6 +173,7 @@ class OPDSXMLReader extends ZLXMLReaderAdapter {
|
|||
private final StringBuffer myBuffer = new StringBuffer();
|
||||
private HtmlToString myHtmlToString = new HtmlToString();
|
||||
|
||||
private boolean myFeedMetadataProcessed;
|
||||
|
||||
@Override
|
||||
public boolean startElementHandler(String tag, ZLStringMap attributes) {
|
||||
|
@ -202,6 +203,7 @@ class OPDSXMLReader extends ZLXMLReaderAdapter {
|
|||
myFeed = new OPDSFeedMetadata();
|
||||
myFeed.readAttributes(attributes);
|
||||
myState = FEED;
|
||||
myFeedMetadataProcessed = false;
|
||||
}
|
||||
break;
|
||||
case FEED:
|
||||
|
@ -236,8 +238,9 @@ class OPDSXMLReader extends ZLXMLReaderAdapter {
|
|||
myEntry.readAttributes(attributes);
|
||||
myState = F_ENTRY;
|
||||
// Process feed metadata just before first feed entry
|
||||
if (myFeed != null && myFeed.Id != null) {
|
||||
if (myFeed != null && myFeed.Id != null && !myFeedMetadataProcessed) {
|
||||
myFeedReader.processFeedMetadata(myFeed, true);
|
||||
myFeedMetadataProcessed = true;
|
||||
}
|
||||
}
|
||||
} else if (tagPrefix == myOpenSearchNamespaceId) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue