mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 10:49:24 +02:00
New OPDS.XML DTD and Catalog loading changes
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1619 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
a2719f033b
commit
903eded8f7
25 changed files with 250 additions and 31 deletions
|
@ -10,8 +10,7 @@ DONE сделать SeekBar (как в ветке alex) в пункте Navigate
|
||||||
|
|
||||||
DONE каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен:
|
DONE каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен:
|
||||||
в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг)
|
в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг)
|
||||||
** по-умолчанию сделать отбрасывание элементов недогруженных страниц
|
DONE по-умолчанию сделать отбрасывание элементов недогруженных страниц (плюс свойство OPDSLink'ов hasStableIdentifiers)
|
||||||
(плюс свойство OPDSLink'ов, подтверждающее стабильность идентификаторов)
|
|
||||||
* 3 иконки в верхнем-правом углу для книжек
|
* 3 иконки в верхнем-правом углу для книжек
|
||||||
|
|
||||||
DONE регистрация новых пользователей -- в диалоге authentication
|
DONE регистрация новых пользователей -- в диалоге authentication
|
||||||
|
|
56
data/network/catalog.dtd
Normal file
56
data/network/catalog.dtd
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<!ELEMENT catalog (site,title,summary?,link+,advancedSearch?,relationAliases?,feeds?,authentication?,urlRewritingRules?,icon)>
|
||||||
|
<!ATTLIST catalog
|
||||||
|
type (opds) #REQUIRED
|
||||||
|
hasStableIdentifiers (true|false) "false"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT site (#PCDATA)>
|
||||||
|
<!ELEMENT title (#PCDATA)>
|
||||||
|
<!ELEMENT summary (#PCDATA)>
|
||||||
|
<!ELEMENT icon (#PCDATA)>
|
||||||
|
|
||||||
|
<!ELEMENT link (#PCDATA)>
|
||||||
|
<!ATTLIST link
|
||||||
|
rel (main|search|signIn|signOut|signUp|refillAccount|recoverPassword) #REQUIRED
|
||||||
|
type CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT relationAliases (alias+)>
|
||||||
|
<!ELEMENT alias EMPTY>
|
||||||
|
<!ATTLIST alias
|
||||||
|
alias CDATA #REQUIRED
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
type CDATA ""
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT advancedSearch (field+)>
|
||||||
|
<!ATTLIST advancedSearch
|
||||||
|
style (separateWords|quoted) #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT field (#PCDATA)>
|
||||||
|
<!ATTLIST field
|
||||||
|
name (author|titleOrSeries|tag|annotation) #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT feeds (condition+)>
|
||||||
|
|
||||||
|
<!ELEMENT condition (#PCDATA)>
|
||||||
|
<!ATTLIST condition
|
||||||
|
show (never|signedIn) #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT authentication EMPTY>
|
||||||
|
<!ATTLIST authentication
|
||||||
|
type (basic|litres) #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ELEMENT urlRewritingRules (rule+)>
|
||||||
|
|
||||||
|
<!ELEMENT rule EMPTY>
|
||||||
|
<!ATTLIST rule
|
||||||
|
type (addUrlParameter) #REQUIRED
|
||||||
|
apply (always|external|internal) "always"
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
value CDATA #REQUIRED
|
||||||
|
>
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE catalog SYSTEM "catalog.dtd">
|
<!DOCTYPE catalog SYSTEM "catalog.dtd">
|
||||||
<catalog type="opds">
|
<catalog type="opds" hasStableIdentifiers="true">
|
||||||
<site>feedbooks.com</site>
|
<site>feedbooks.com</site>
|
||||||
<title>Feedbooks OPDS Catalog</title>
|
<title>Feedbooks OPDS Catalog</title>
|
||||||
<summary>Feedbooks: Food for the mind. A place to discover and publish e-books.</summary>
|
<summary>Feedbooks: Food for the mind. A place to discover and publish e-books.</summary>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE catalog SYSTEM "catalog.dtd">
|
<!DOCTYPE catalog SYSTEM "catalog.dtd">
|
||||||
<catalog type="opds">
|
<catalog type="opds" hasStableIdentifiers="true">
|
||||||
<site>litres.ru</site>
|
<site>litres.ru</site>
|
||||||
<title>Каталог LitRes</title>
|
<title>Каталог LitRes</title>
|
||||||
<summary>Продажа электронных книг.</summary>
|
<summary>Продажа электронных книг.</summary>
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.geometerplus.android.fbreader.network;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||||
import org.geometerplus.fbreader.network.NetworkTree;
|
import org.geometerplus.fbreader.network.NetworkTree;
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,4 +40,9 @@ public class AddCustomCatalogItemTree extends NetworkTree {
|
||||||
public String getSummary() {
|
public String getSummary() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,16 @@
|
||||||
|
|
||||||
package org.geometerplus.android.fbreader.network;
|
package org.geometerplus.android.fbreader.network;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.network.INetworkLink;
|
||||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,15 +38,31 @@ abstract class ItemsLoadingHandler extends Handler {
|
||||||
private static final int WHAT_FINISHED = 1;
|
private static final int WHAT_FINISHED = 1;
|
||||||
|
|
||||||
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
|
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
|
||||||
|
private final HashMap<INetworkLink, LinkedList<NetworkLibraryItem>> myUncommitedItems = new HashMap<INetworkLink, LinkedList<NetworkLibraryItem>>();
|
||||||
private final Object myItemsMonitor = new Object();
|
private final Object myItemsMonitor = new Object();
|
||||||
|
|
||||||
private volatile boolean myFinishProcessed;
|
private volatile boolean myFinishProcessed;
|
||||||
private final Object myFinishMonitor = new Object();
|
private final Object myFinishMonitor = new Object();
|
||||||
|
|
||||||
|
|
||||||
public final void addItem(NetworkLibraryItem item) {
|
public final void addItem(INetworkLink link, NetworkLibraryItem item) {
|
||||||
synchronized (myItemsMonitor) {
|
synchronized (myItemsMonitor) {
|
||||||
myItems.add(item);
|
myItems.add(item);
|
||||||
|
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
|
||||||
|
if (uncommited == null) {
|
||||||
|
uncommited = new LinkedList<NetworkLibraryItem>();
|
||||||
|
myUncommitedItems.put(link, uncommited);
|
||||||
|
}
|
||||||
|
uncommited.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void commitItems(INetworkLink link) {
|
||||||
|
synchronized (myItemsMonitor) {
|
||||||
|
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
|
||||||
|
if (uncommited != null) {
|
||||||
|
uncommited.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +98,14 @@ abstract class ItemsLoadingHandler extends Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void doProcessFinish(String errorMessage, boolean interrupted) {
|
private final void doProcessFinish(String errorMessage, boolean interrupted) {
|
||||||
|
HashSet<NetworkLibraryItem> uncommitedItems = new HashSet<NetworkLibraryItem>();
|
||||||
|
synchronized (myUncommitedItems) {
|
||||||
|
for (LinkedList<NetworkLibraryItem> items: myUncommitedItems.values()) {
|
||||||
|
uncommitedItems.addAll(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
synchronized (myFinishMonitor) {
|
synchronized (myFinishMonitor) {
|
||||||
onFinish(errorMessage, interrupted);
|
onFinish(errorMessage, interrupted, uncommitedItems);
|
||||||
myFinishProcessed = true;
|
myFinishProcessed = true;
|
||||||
myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
|
myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +126,7 @@ abstract class ItemsLoadingHandler extends Handler {
|
||||||
// callbacks
|
// callbacks
|
||||||
public abstract void onUpdateItems(List<NetworkLibraryItem> items);
|
public abstract void onUpdateItems(List<NetworkLibraryItem> items);
|
||||||
public abstract void afterUpdateItems();
|
public abstract void afterUpdateItems();
|
||||||
public abstract void onFinish(String errorMessage, boolean interrupted);
|
public abstract void onFinish(String errorMessage, boolean interrupted, Set<NetworkLibraryItem> uncommitedItems);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,6 +22,7 @@ package org.geometerplus.android.fbreader.network;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.network.INetworkLink;
|
||||||
import org.geometerplus.fbreader.network.NetworkOperationData;
|
import org.geometerplus.fbreader.network.NetworkOperationData;
|
||||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||||
|
|
||||||
|
@ -98,8 +99,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
||||||
err = doLoading(new NetworkOperationData.OnNewItemListener() {
|
err = doLoading(new NetworkOperationData.OnNewItemListener() {
|
||||||
private long myUpdateTime;
|
private long myUpdateTime;
|
||||||
private int myItemsNumber;
|
private int myItemsNumber;
|
||||||
public void onNewItem(NetworkLibraryItem item) {
|
public void onNewItem(INetworkLink link, NetworkLibraryItem item) {
|
||||||
myHandler.addItem(item);
|
myHandler.addItem(link, item);
|
||||||
++myItemsNumber;
|
++myItemsNumber;
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
if (now > myUpdateTime) {
|
if (now > myUpdateTime) {
|
||||||
|
@ -110,6 +111,9 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
||||||
public boolean confirmInterrupt() {
|
public boolean confirmInterrupt() {
|
||||||
return confirmInterruptLoading() || myItemsNumber >= ItemsLimit;
|
return confirmInterruptLoading() || myItemsNumber >= ItemsLimit;
|
||||||
}
|
}
|
||||||
|
public void commitItems(INetworkLink link) {
|
||||||
|
myHandler.commitItems(link);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
myHandler.sendUpdateItems();
|
myHandler.sendUpdateItems();
|
||||||
myHandler.ensureItemsProcessed();
|
myHandler.ensureItemsProcessed();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.geometerplus.android.fbreader.network;
|
package org.geometerplus.android.fbreader.network;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
@ -274,6 +275,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
||||||
myKey = key;
|
myKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
||||||
for (NetworkLibraryItem item: items) {
|
for (NetworkLibraryItem item: items) {
|
||||||
myTree.ChildrenItems.add(item);
|
myTree.ChildrenItems.add(item);
|
||||||
|
@ -281,20 +283,26 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void afterUpdateItems() {
|
public void afterUpdateItems() {
|
||||||
if (NetworkView.Instance().isInitialized()) {
|
if (NetworkView.Instance().isInitialized()) {
|
||||||
NetworkView.Instance().fireModelChanged();
|
NetworkView.Instance().fireModelChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFinish(String errorMessage, boolean interrupted) {
|
@Override
|
||||||
|
public void onFinish(String errorMessage, boolean interrupted,
|
||||||
|
Set<NetworkLibraryItem> uncommitedItems) {
|
||||||
if (interrupted &&
|
if (interrupted &&
|
||||||
(!myTree.Item.supportsResumeLoading() || errorMessage != null)) {
|
(!myTree.Item.supportsResumeLoading() || errorMessage != null)) {
|
||||||
myTree.ChildrenItems.clear();
|
myTree.ChildrenItems.clear();
|
||||||
myTree.clear();
|
myTree.clear();
|
||||||
} else {
|
} else {
|
||||||
|
myTree.removeItems(uncommitedItems);
|
||||||
myTree.updateLoadedTime();
|
myTree.updateLoadedTime();
|
||||||
|
if (!interrupted) {
|
||||||
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
|
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
|
||||||
|
}
|
||||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||||
library.invalidateVisibility();
|
library.invalidateVisibility();
|
||||||
library.synchronize();
|
library.synchronize();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.geometerplus.android.fbreader.network;
|
package org.geometerplus.android.fbreader.network;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
@ -62,6 +63,7 @@ public class NetworkSearchActivity extends Activity {
|
||||||
myTree = tree;
|
myTree = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
||||||
SearchResult result = myTree.getSearchResult();
|
SearchResult result = myTree.getSearchResult();
|
||||||
for (NetworkLibraryItem item: items) {
|
for (NetworkLibraryItem item: items) {
|
||||||
|
@ -71,6 +73,7 @@ public class NetworkSearchActivity extends Activity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void afterUpdateItems() {
|
public void afterUpdateItems() {
|
||||||
myTree.updateSubTrees();
|
myTree.updateSubTrees();
|
||||||
if (NetworkView.Instance().isInitialized()) {
|
if (NetworkView.Instance().isInitialized()) {
|
||||||
|
@ -78,7 +81,9 @@ public class NetworkSearchActivity extends Activity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFinish(String errorMessage, boolean interrupted) {
|
@Override
|
||||||
|
public void onFinish(String errorMessage, boolean interrupted,
|
||||||
|
Set<NetworkLibraryItem> uncommitedItems) {
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
myTree.setSearchResult(null);
|
myTree.setSearchResult(null);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||||
import org.geometerplus.zlibrary.core.util.ZLBoolean3;
|
import org.geometerplus.zlibrary.core.util.ZLBoolean3;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.network.INetworkLink;
|
import org.geometerplus.fbreader.network.INetworkLink;
|
||||||
|
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||||
import org.geometerplus.fbreader.network.NetworkTree;
|
import org.geometerplus.fbreader.network.NetworkTree;
|
||||||
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
|
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
|
||||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||||
|
@ -61,4 +62,9 @@ class RefillAccountTree extends NetworkTree {
|
||||||
protected ZLImage createCover() {
|
protected ZLImage createCover() {
|
||||||
return Cover;
|
return Cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,4 +99,9 @@ public class SearchItemTree extends NetworkTree {
|
||||||
throw new RuntimeException("That's impossible!!!");
|
throw new RuntimeException("That's impossible!!!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,12 +411,15 @@ public class NetworkLibrary {
|
||||||
LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>();
|
LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>();
|
||||||
|
|
||||||
final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
|
final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
|
||||||
public synchronized void onNewItem(NetworkLibraryItem item) {
|
public synchronized void onNewItem(INetworkLink link, NetworkLibraryItem item) {
|
||||||
listener.onNewItem(item);
|
listener.onNewItem(link, item);
|
||||||
}
|
}
|
||||||
public synchronized boolean confirmInterrupt() {
|
public synchronized boolean confirmInterrupt() {
|
||||||
return listener.confirmInterrupt();
|
return listener.confirmInterrupt();
|
||||||
}
|
}
|
||||||
|
public synchronized void commitItems(INetworkLink link) {
|
||||||
|
listener.commitItems(link);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
synchronized (myLinks) {
|
synchronized (myLinks) {
|
||||||
|
|
|
@ -25,9 +25,12 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
||||||
public class NetworkOperationData {
|
public class NetworkOperationData {
|
||||||
|
|
||||||
public interface OnNewItemListener {
|
public interface OnNewItemListener {
|
||||||
void onNewItem(NetworkLibraryItem item);
|
void onNewItem(INetworkLink link, NetworkLibraryItem item);
|
||||||
|
|
||||||
// return true to confirm interrupt reading; return false to continue reading
|
void commitItems(INetworkLink link);
|
||||||
|
|
||||||
|
// returns true to confirm interrupt reading; return false to continue reading.
|
||||||
|
// once true has been returned, all next calls must return true.
|
||||||
boolean confirmInterrupt();
|
boolean confirmInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.network;
|
package org.geometerplus.fbreader.network;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.tree.FBTree;
|
import org.geometerplus.fbreader.tree.FBTree;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.image.ZLImage;
|
import org.geometerplus.zlibrary.core.image.ZLImage;
|
||||||
|
@ -80,4 +83,33 @@ public abstract class NetworkTree extends FBTree {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract NetworkLibraryItem getHoldedItem();
|
||||||
|
|
||||||
|
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||||
|
if (items.isEmpty() || subTrees().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final LinkedList<FBTree> treesList = new LinkedList<FBTree>();
|
||||||
|
for (FBTree tree: subTrees()) {
|
||||||
|
final NetworkLibraryItem treeItem = ((NetworkTree)tree).getHoldedItem();
|
||||||
|
if (treeItem != null && items.contains(treeItem)) {
|
||||||
|
treesList.add(tree);
|
||||||
|
items.remove(treeItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FBTree tree: treesList) {
|
||||||
|
tree.removeSelf();
|
||||||
|
}
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
treesList.clear();
|
||||||
|
treesList.addAll(subTrees());
|
||||||
|
while (!treesList.isEmpty()) {
|
||||||
|
final NetworkTree tree = (NetworkTree) treesList.remove(treesList.size() - 1);
|
||||||
|
tree.removeItems(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,9 @@ public class LitResBookshelfItem extends NetworkCatalogItem {
|
||||||
mgr.collectPurchasedBooks(children);
|
mgr.collectPurchasedBooks(children);
|
||||||
Collections.sort(children, new NetworkBookItemComparator());
|
Collections.sort(children, new NetworkBookItemComparator());
|
||||||
for (NetworkLibraryItem item: children) {
|
for (NetworkLibraryItem item: children) {
|
||||||
listener.onNewItem(item);
|
listener.onNewItem(Link, item);
|
||||||
}
|
}
|
||||||
|
listener.commitItems(Link);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||||
private int myIndex;
|
private int myIndex;
|
||||||
|
|
||||||
private String myNextURL;
|
private String myNextURL;
|
||||||
private String mySkipUntilTitle;
|
private String mySkipUntilId;
|
||||||
|
|
||||||
private int myItemsToLoad = -1;
|
private int myItemsToLoad = -1;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||||
NetworkOPDSFeedReader(String baseURL, OPDSCatalogItem.State result) {
|
NetworkOPDSFeedReader(String baseURL, OPDSCatalogItem.State result) {
|
||||||
myBaseURL = baseURL;
|
myBaseURL = baseURL;
|
||||||
myData = result;
|
myData = result;
|
||||||
mySkipUntilTitle = myData.LastLoadedTitle;
|
mySkipUntilId = myData.LastLoadedId;
|
||||||
if (!(result.Link instanceof OPDSLink)) {
|
if (!(result.Link instanceof OPDSLink)) {
|
||||||
throw new IllegalArgumentException("Parameter `result` has invalid `Link` field value: result.Link must be an instance of OPDSLink class.");
|
throw new IllegalArgumentException("Parameter `result` has invalid `Link` field value: result.Link must be an instance of OPDSLink class.");
|
||||||
}
|
}
|
||||||
|
@ -91,14 +91,14 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processFeedEnd() {
|
public void processFeedEnd() {
|
||||||
if (mySkipUntilTitle != null) {
|
if (mySkipUntilId != null) {
|
||||||
// Last loaded element was not found => resume error => DO NOT RESUME
|
// Last loaded element was not found => resume error => DO NOT RESUME
|
||||||
// TODO: notify user about error???
|
// TODO: notify user about error???
|
||||||
// TODO: do reload???
|
// TODO: do reload???
|
||||||
myNextURL = null;
|
myNextURL = null;
|
||||||
}
|
}
|
||||||
myData.ResumeURI = myNextURL;
|
myData.ResumeURI = myNextURL;
|
||||||
myData.LastLoadedTitle = null;
|
myData.LastLoadedId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,13 +142,13 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||||
--myItemsToLoad;
|
--myItemsToLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mySkipUntilTitle != null) {
|
if (mySkipUntilId != null) {
|
||||||
if (mySkipUntilTitle.equals(entry.Title)) {
|
if (mySkipUntilId.equals(entry.Id.Uri)) {
|
||||||
mySkipUntilTitle = null;
|
mySkipUntilId = null;
|
||||||
}
|
}
|
||||||
return tryInterrupt();
|
return tryInterrupt();
|
||||||
}
|
}
|
||||||
myData.LastLoadedTitle = entry.Title;
|
myData.LastLoadedId = entry.Id.Uri;
|
||||||
|
|
||||||
final OPDSLink opdsLink = (OPDSLink) myData.Link;
|
final OPDSLink opdsLink = (OPDSLink) myData.Link;
|
||||||
if (opdsLink.getCondition(entry.Id.Uri) == OPDSLink.FeedCondition.NEVER) {
|
if (opdsLink.getCondition(entry.Id.Uri) == OPDSLink.FeedCondition.NEVER) {
|
||||||
|
@ -176,7 +176,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
|
||||||
item = readCatalogItem(entry);
|
item = readCatalogItem(entry);
|
||||||
}
|
}
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
myData.Listener.onNewItem(item);
|
myData.Listener.onNewItem(myData.Link, item);
|
||||||
}
|
}
|
||||||
return tryInterrupt();
|
return tryInterrupt();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class OPDSCatalogItem extends NetworkCatalogItem {
|
||||||
|
|
||||||
static class State extends NetworkOperationData {
|
static class State extends NetworkOperationData {
|
||||||
|
|
||||||
public String LastLoadedTitle;
|
public String LastLoadedId;
|
||||||
|
|
||||||
public State(INetworkLink link, OnNewItemListener listener) {
|
public State(INetworkLink link, OnNewItemListener listener) {
|
||||||
super(link, listener);
|
super(link, listener);
|
||||||
|
|
|
@ -30,7 +30,7 @@ class OPDSCustomLink extends OPDSLink implements ICustomNetworkLink {
|
||||||
private SaveLinkListener myListener;
|
private SaveLinkListener myListener;
|
||||||
|
|
||||||
OPDSCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) {
|
OPDSCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) {
|
||||||
super(siteName, title, summary, icon, links);
|
super(siteName, title, summary, icon, links, false);
|
||||||
myId = id;
|
myId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,12 @@ class OPDSLink extends AbstractNetworkLink {
|
||||||
private LinkedList<URLRewritingRule> myUrlRewritingRules;
|
private LinkedList<URLRewritingRule> myUrlRewritingRules;
|
||||||
private NetworkAuthenticationManager myAuthenticationManager;
|
private NetworkAuthenticationManager myAuthenticationManager;
|
||||||
|
|
||||||
OPDSLink(String siteName, String title, String summary, String icon, Map<String, String> links) {
|
private final boolean myHasStableIdentifiers;
|
||||||
|
|
||||||
|
OPDSLink(String siteName, String title, String summary, String icon,
|
||||||
|
Map<String, String> links, boolean hasStableIdentifiers) {
|
||||||
super(siteName, title, summary, icon, links);
|
super(siteName, title, summary, icon, links);
|
||||||
|
myHasStableIdentifiers = hasStableIdentifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
final void setRelationAliases(Map<RelationAlias, String> relationAliases) {
|
final void setRelationAliases(Map<RelationAlias, String> relationAliases) {
|
||||||
|
@ -88,9 +92,23 @@ class OPDSLink extends AbstractNetworkLink {
|
||||||
if (result.Listener.confirmInterrupt()) {
|
if (result.Listener.confirmInterrupt()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
new OPDSXMLReader(
|
new OPDSXMLReader(
|
||||||
new NetworkOPDSFeedReader(URL, result)
|
new NetworkOPDSFeedReader(URL, result)
|
||||||
).read(inputStream);
|
).read(inputStream);
|
||||||
|
|
||||||
|
if (result.Listener.confirmInterrupt()) {
|
||||||
|
if (!myHasStableIdentifiers && result.LastLoadedId != null) {
|
||||||
|
// If current catalog doesn't have stable identifiers
|
||||||
|
// and catalog wasn't completely loaded (i.e. LastLoadedIdentifier is not null)
|
||||||
|
// then reset state to load current page from the beginning
|
||||||
|
result.LastLoadedId = null;
|
||||||
|
} else {
|
||||||
|
result.Listener.commitItems(OPDSLink.this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.Listener.commitItems(OPDSLink.this);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
|
||||||
private String myTitle;
|
private String myTitle;
|
||||||
private String mySummary;
|
private String mySummary;
|
||||||
private String myIcon;
|
private String myIcon;
|
||||||
|
private boolean myHasStableIdentifiers;
|
||||||
|
|
||||||
private final HashMap<String, String> myLinks = new HashMap<String, String>();
|
private final HashMap<String, String> myLinks = new HashMap<String, String>();
|
||||||
|
|
||||||
|
@ -60,7 +61,8 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
|
||||||
myTitle,
|
myTitle,
|
||||||
mySummary,
|
mySummary,
|
||||||
myIcon,
|
myIcon,
|
||||||
myLinks
|
myLinks,
|
||||||
|
myHasStableIdentifiers
|
||||||
);
|
);
|
||||||
|
|
||||||
/*if (!mySearchType.empty()) {
|
/*if (!mySearchType.empty()) {
|
||||||
|
@ -102,6 +104,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
|
||||||
|
|
||||||
public INetworkLink readDocument(ZLFile file) {
|
public INetworkLink readDocument(ZLFile file) {
|
||||||
mySiteName = myTitle = mySummary = myIcon = /*mySearchType = */myAuthenticationType = mySSLCertificate = null;
|
mySiteName = myTitle = mySummary = myIcon = /*mySearchType = */myAuthenticationType = mySSLCertificate = null;
|
||||||
|
myHasStableIdentifiers = false;
|
||||||
myLinks.clear();
|
myLinks.clear();
|
||||||
mySearchFields.clear();
|
mySearchFields.clear();
|
||||||
myUrlConditions.clear();
|
myUrlConditions.clear();
|
||||||
|
@ -126,6 +129,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final String TAG_CATALOG = "catalog";
|
||||||
private static final String TAG_SITE = "site";
|
private static final String TAG_SITE = "site";
|
||||||
private static final String TAG_LINK = "link";
|
private static final String TAG_LINK = "link";
|
||||||
private static final String TAG_TITLE = "title";
|
private static final String TAG_TITLE = "title";
|
||||||
|
@ -163,7 +167,10 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
|
||||||
@Override
|
@Override
|
||||||
public boolean startElementHandler(String tag, ZLStringMap attributes) {
|
public boolean startElementHandler(String tag, ZLStringMap attributes) {
|
||||||
tag = tag.intern();
|
tag = tag.intern();
|
||||||
if (TAG_SITE == tag) {
|
if (TAG_CATALOG == tag) {
|
||||||
|
final String value = attributes.getValue("hasStableIdentifiers");
|
||||||
|
myHasStableIdentifiers = value != null && value.equals("true");
|
||||||
|
} else if (TAG_SITE == tag) {
|
||||||
myState = READ_SITENAME;
|
myState = READ_SITENAME;
|
||||||
} else if (TAG_TITLE == tag) {
|
} else if (TAG_TITLE == tag) {
|
||||||
myState = READ_TITLE;
|
myState = READ_TITLE;
|
||||||
|
|
|
@ -118,4 +118,9 @@ public class NetworkAuthorTree extends NetworkTree {
|
||||||
|
|
||||||
myBooksNumber = books.size();
|
myBooksNumber = books.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,4 +67,9 @@ public class NetworkBookTree extends NetworkTree {
|
||||||
protected ZLImage createCover() {
|
protected ZLImage createCover() {
|
||||||
return createCover(Book);
|
return createCover(Book);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return Book;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,4 +156,15 @@ public class NetworkCatalogTree extends NetworkTree {
|
||||||
tree.removeSelf();
|
tree.removeSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||||
|
ChildrenItems.removeAll(items);
|
||||||
|
super.removeItems(items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,4 +85,17 @@ public class NetworkSeriesTree extends NetworkTree {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||||
|
super.removeItems(items);
|
||||||
|
if (subTrees().isEmpty()) {
|
||||||
|
removeSelf();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.network.tree;
|
package org.geometerplus.fbreader.network.tree;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||||
import org.geometerplus.fbreader.network.NetworkTree;
|
import org.geometerplus.fbreader.network.NetworkTree;
|
||||||
|
|
||||||
public final class RootTree extends NetworkTree {
|
public final class RootTree extends NetworkTree {
|
||||||
|
@ -26,4 +27,9 @@ public final class RootTree extends NetworkTree {
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkLibraryItem getHoldedItem() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue