1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 02:39:23 +02:00

sync tree in library + fixed filters

This commit is contained in:
Nikolay Pultsin 2014-07-23 10:23:10 +01:00
parent f0e58a87af
commit 30ed81658a
11 changed files with 236 additions and 15 deletions

View file

@ -26,6 +26,21 @@
<node name="found" value="Found">
<node name="summary" value="Search results for: %s"/>
</node>
<node name="sync" value="Synchronization">
<node name="summary" value="Books by synchronization status"/>
<node name="sync-success" value="Synchronized">
<node name="summary" value="Books uploaded to the server"/>
</node>
<node name="sync-failure" value="Synchronization failed">
<node name="summary" value="Long tap this item to select action"/>
</node>
<node name="sync-deleted" value="Deleted from server">
<node name="summary" value="Long tap this item to select action"/>
</node>
<node name="sync-tosync" value="Not synchronized yet">
<node name="summary" value="Books to be uploaded to the server"/>
</node>
</node>
<node name="fileTree" value="File tree">
<node name="summary" value="Browse file system"/>
</node>

View file

@ -97,7 +97,7 @@ class LibraryTreeAdapter extends TreeAdapter {
return R.drawable.ic_list_library_book;
} else if (tree instanceof FavoritesTree) {
return R.drawable.ic_list_library_favorites;
} else if (tree instanceof RecentBooksTree) {
} else if (tree instanceof RecentBooksTree || tree instanceof SyncTree) {
return R.drawable.ic_list_library_recent;
} else if (tree instanceof AuthorListTree) {
return R.drawable.ic_list_library_authors;

View file

@ -37,11 +37,25 @@ import org.geometerplus.android.fbreader.network.auth.ServiceNetworkContext;
public class SynchroniserService extends Service implements IBookCollection.Listener, Runnable {
enum SyncStatus {
AlreadyUploaded,
Uploaded,
ToBeDeleted,
Failure,
HashNotComputed
AlreadyUploaded(Book.SYNCHRONIZED_LABEL),
Uploaded(Book.SYNCHRONIZED_LABEL),
ToBeDeleted(Book.SYNC_DELETED_LABEL),
Failure(Book.SYNC_FAILURE_LABEL),
FailedPreviuousTime(null),
HashNotComputed(null);
private static final List<String> AllLabels = Arrays.asList(
Book.SYNCHRONIZED_LABEL,
Book.SYNC_FAILURE_LABEL,
Book.SYNC_DELETED_LABEL,
Book.SYNC_TOSYNC_LABEL
);
public final String Label;
SyncStatus(String label) {
Label = label;
}
}
private final ZLNetworkContext myNetworkContext = new ServiceNetworkContext(this);
@ -110,6 +124,16 @@ public class SynchroniserService extends Service implements IBookCollection.List
myProcessed.add(book);
++count;
final SyncStatus status = uploadBookToServer(book);
if (status.Label != null) {
for (String label : SyncStatus.AllLabels) {
if (status.Label.equals(label)) {
book.addLabel(label);
} else {
book.removeLabel(label);
}
}
myCollection.saveBook(book);
}
final Integer sc = statusCounts.get(status);
statusCounts.put(status, sc != null ? sc + 1 : 1);
}
@ -190,12 +214,12 @@ public class SynchroniserService extends Service implements IBookCollection.List
final String hash = myCollection.getHash(book);
if (hash == null) {
return SyncStatus.HashNotComputed;
}
if (myActualHashesFromServer.contains(hash)) {
} else if (myActualHashesFromServer.contains(hash)) {
return SyncStatus.AlreadyUploaded;
}
if (myDeletedHashesFromServer.contains(hash)) {
} else if (myDeletedHashesFromServer.contains(hash)) {
return SyncStatus.ToBeDeleted;
} else if (book.labels().contains(Book.SYNC_FAILURE_LABEL)) {
return SyncStatus.FailedPreviuousTime;
}
final Map<String,Object> result = new HashMap<String,Object>();
final PostRequest verificationRequest =

View file

@ -34,6 +34,10 @@ import org.geometerplus.fbreader.sort.TitledEntity;
public class Book extends TitledEntity {
public static final String FAVORITE_LABEL = "favorite";
public static final String READ_LABEL = "read";
public static final String SYNCHRONIZED_LABEL = "sync-success";
public static final String SYNC_FAILURE_LABEL = "sync-failure";
public static final String SYNC_DELETED_LABEL = "sync-deleted";
public static final String SYNC_TOSYNC_LABEL = "sync-tosync";
public final ZLFile File;

View file

@ -140,4 +140,16 @@ public abstract class Filter {
return First.matches(book) || Second.matches(book);
}
}
public final static class Not extends Filter {
public final Filter Base;
public Not(Filter base) {
Base = base;
}
public boolean matches(Book book) {
return !Base.matches(book);
}
}
}

View file

@ -52,6 +52,10 @@ class XMLSerializer extends AbstractSerializer {
appendTag(buffer, "filter", true,
"type", "empty"
);
} else if (filter instanceof Filter.Not) {
appendTag(buffer, "not", false);
serialize(buffer, ((Filter.Not)filter).Base);
closeTag(buffer, "not");
} else if (filter instanceof Filter.And) {
appendTag(buffer, "and", false);
serialize(buffer, ((Filter.And)filter).First);
@ -686,6 +690,7 @@ class XMLSerializer extends AbstractSerializer {
private static final class BookQueryDeserializer extends DefaultHandler {
private static enum State {
READ_QUERY,
READ_FILTER_NOT,
READ_FILTER_AND,
READ_FILTER_OR,
READ_FILTER_SIMPLE
@ -714,6 +719,12 @@ class XMLSerializer extends AbstractSerializer {
}
}
private void setFilterToStack() {
if (!myFilterStack.isEmpty() && myFilterStack.getLast() == null) {
myFilterStack.set(myFilterStack.size() - 1, myFilter);
}
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (myStateStack.isEmpty()) {
@ -759,10 +770,10 @@ class XMLSerializer extends AbstractSerializer {
// to keep a door to add new filters in a future
myFilter = new Filter.Empty();
}
if (!myFilterStack.isEmpty() && myFilterStack.getLast() == null) {
myFilterStack.set(myFilterStack.size() - 1, myFilter);
}
myStateStack.add(State.READ_FILTER_SIMPLE);
} else if ("not".equals(localName)) {
myFilterStack.add(null);
myStateStack.add(State.READ_FILTER_NOT);
} else if ("and".equals(localName)) {
myFilterStack.add(null);
myStateStack.add(State.READ_FILTER_AND);
@ -784,6 +795,9 @@ class XMLSerializer extends AbstractSerializer {
switch (myStateStack.removeLast()) {
case READ_QUERY:
break;
case READ_FILTER_NOT:
myFilter = new Filter.Not(myFilterStack.removeLast());
break;
case READ_FILTER_AND:
myFilter = new Filter.And(myFilterStack.removeLast(), myFilter);
break;
@ -793,6 +807,7 @@ class XMLSerializer extends AbstractSerializer {
case READ_FILTER_SIMPLE:
break;
}
setFilterToStack();
}
}

View file

@ -26,7 +26,7 @@ import org.geometerplus.fbreader.Paths;
public class FileFirstLevelTree extends FirstLevelTree {
FileFirstLevelTree(RootTree root) {
super(root, ROOT_FILE_TREE);
super(root, ROOT_FILE);
}
@Override

View file

@ -40,7 +40,8 @@ public abstract class LibraryTree extends FBTree {
static final String ROOT_BY_TITLE = "byTitle";
static final String ROOT_BY_SERIES = "bySeries";
static final String ROOT_BY_TAG = "byTag";
static final String ROOT_FILE_TREE = "fileTree";
static final String ROOT_SYNC = "sync";
static final String ROOT_FILE = "fileTree";
protected LibraryTree(IBookCollection collection) {
super();

View file

@ -31,6 +31,7 @@ public class RootTree extends LibraryTree {
new TitleListTree(this);
new SeriesListTree(this);
new TagListTree(this);
new SyncTree(this);
new FileFirstLevelTree(this);
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2009-2014 Geometer Plus <contact@geometerplus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.library;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.Filter;
public class SyncLabelTree extends FilteredTree {
private final String myLabel;
private final ZLResource myResource;
SyncLabelTree(SyncTree parent, String label, Filter filter, ZLResource resource) {
super(parent, filter, -1);
myLabel = label;
myResource = resource;
}
@Override
public String getName() {
return myResource.getValue();
}
@Override
public String getTreeTitle() {
return getSummary();
}
@Override
public String getSummary() {
return myResource.getResource("summary").getValue();
}
@Override
protected String getStringId() {
return "@SyncLabelTree " + myLabel;
}
@Override
public boolean isSelectable() {
return false;
}
@Override
public Status getOpeningStatus() {
return Status.ALWAYS_RELOAD_BEFORE_OPENING;
}
@Override
protected boolean createSubtree(Book book) {
return createBookWithAuthorsSubtree(book);
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2009-2014 Geometer Plus <contact@geometerplus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.library;
import java.util.Arrays;
import java.util.List;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.Filter;
public class SyncTree extends FirstLevelTree {
private final List<String> myLabels = Arrays.asList(
Book.SYNCHRONIZED_LABEL,
Book.SYNC_FAILURE_LABEL,
Book.SYNC_DELETED_LABEL
);
SyncTree(RootTree root) {
super(root, ROOT_SYNC);
}
@Override
public String getTreeTitle() {
return getName();
}
@Override
public Status getOpeningStatus() {
return Status.ALWAYS_RELOAD_BEFORE_OPENING;
}
@Override
public void waitForOpening() {
clear();
final ZLResource baseResource = resource().getResource(ROOT_SYNC);
Filter others = null;
for (String label : myLabels) {
final Filter filter = new Filter.ByLabel(label);
if (Collection.hasBooks(filter)) {
new SyncLabelTree(this, label, filter, baseResource.getResource(label));
}
if (others == null) {
others = new Filter.Not(filter);
} else {
others = new Filter.And(others, new Filter.Not(filter));
}
}
if (Collection.hasBooks(others)) {
new SyncLabelTree(
this,
Book.SYNC_TOSYNC_LABEL,
others,
baseResource.getResource(Book.SYNC_TOSYNC_LABEL)
);
}
}
}