diff --git a/assets/resources/application/en.xml b/assets/resources/application/en.xml
index daa279691..109b9201b 100644
--- a/assets/resources/application/en.xml
+++ b/assets/resources/application/en.xml
@@ -53,10 +53,8 @@
-
-
-
-
+
+
@@ -66,6 +64,8 @@
+
+
@@ -849,6 +849,10 @@
+
+
+
+
diff --git a/src/org/geometerplus/android/fbreader/library/LibraryActivity.java b/src/org/geometerplus/android/fbreader/library/LibraryActivity.java
index eac2e4cae..446ccf529 100644
--- a/src/org/geometerplus/android/fbreader/library/LibraryActivity.java
+++ b/src/org/geometerplus/android/fbreader/library/LibraryActivity.java
@@ -19,7 +19,7 @@
package org.geometerplus.android.fbreader.library;
-import java.util.List;
+import java.util.*;
import android.app.AlertDialog;
import android.app.SearchManager;
@@ -154,10 +154,7 @@ public class LibraryActivity extends TreeActivity implements MenuIt
return true;
}
- //
- // Context menu
- //
- private interface ItemId {
+ private interface ContextItemId {
int OpenBook = 0;
int ShowBookInfo = 1;
int ShareBook = 2;
@@ -168,6 +165,12 @@ public class LibraryActivity extends TreeActivity implements MenuIt
int DeleteBook = 7;
int SyncAgain = 8;
}
+ private interface OptionsItemId {
+ int Search = 0;
+ int Rescan = 1;
+ int SyncAgain = 2;
+ int DeleteAll = 3;
+ }
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
@@ -182,26 +185,26 @@ public class LibraryActivity extends TreeActivity implements MenuIt
final ZLResource resource = LibraryTree.resource();
final List labels = book.labels();
menu.setHeaderTitle(book.getTitle());
- menu.add(0, ItemId.OpenBook, 0, resource.getResource("openBook").getValue());
- menu.add(0, ItemId.ShowBookInfo, 0, resource.getResource("showBookInfo").getValue());
+ menu.add(0, ContextItemId.OpenBook, 0, resource.getResource("openBook").getValue());
+ menu.add(0, ContextItemId.ShowBookInfo, 0, resource.getResource("showBookInfo").getValue());
if (book.File.getPhysicalFile() != null) {
- menu.add(0, ItemId.ShareBook, 0, resource.getResource("shareBook").getValue());
+ menu.add(0, ContextItemId.ShareBook, 0, resource.getResource("shareBook").getValue());
}
if (labels.contains(Book.FAVORITE_LABEL)) {
- menu.add(0, ItemId.RemoveFromFavorites, 0, resource.getResource("removeFromFavorites").getValue());
+ menu.add(0, ContextItemId.RemoveFromFavorites, 0, resource.getResource("removeFromFavorites").getValue());
} else {
- menu.add(0, ItemId.AddToFavorites, 0, resource.getResource("addToFavorites").getValue());
+ menu.add(0, ContextItemId.AddToFavorites, 0, resource.getResource("addToFavorites").getValue());
}
if (labels.contains(Book.READ_LABEL)) {
- menu.add(0, ItemId.MarkAsUnread, 0, resource.getResource("markAsUnread").getValue());
+ menu.add(0, ContextItemId.MarkAsUnread, 0, resource.getResource("markAsUnread").getValue());
} else {
- menu.add(0, ItemId.MarkAsRead, 0, resource.getResource("markAsRead").getValue());
+ menu.add(0, ContextItemId.MarkAsRead, 0, resource.getResource("markAsRead").getValue());
}
if (BookUtil.canRemoveBookFile(book)) {
- menu.add(0, ItemId.DeleteBook, 0, resource.getResource("deleteBook").getValue());
+ menu.add(0, ContextItemId.DeleteBook, 0, resource.getResource("deleteBook").getValue());
}
if (labels.contains(Book.SYNC_FAILURE_LABEL) || labels.contains(Book.SYNC_DELETED_LABEL)) {
- menu.add(0, ItemId.SyncAgain, 0, resource.getResource("syncAgain").getValue());
+ menu.add(0, ContextItemId.SyncAgain, 0, resource.getResource("syncAgain").getValue());
}
}
@@ -215,46 +218,50 @@ public class LibraryActivity extends TreeActivity implements MenuIt
return super.onContextItemSelected(item);
}
+ private void syncAgain(Book book) {
+ book.removeLabel(Book.SYNC_FAILURE_LABEL);
+ book.removeLabel(Book.SYNC_DELETED_LABEL);
+ book.addLabel(Book.SYNC_TOSYNC_LABEL);
+ myRootTree.Collection.saveBook(book);
+ }
+
private boolean onContextItemSelected(int itemId, Book book) {
switch (itemId) {
- case ItemId.OpenBook:
+ case ContextItemId.OpenBook:
FBReader.openBookActivity(this, book, null);
return true;
- case ItemId.ShowBookInfo:
+ case ContextItemId.ShowBookInfo:
showBookInfo(book);
return true;
- case ItemId.ShareBook:
+ case ContextItemId.ShareBook:
FBUtil.shareBook(this, book);
return true;
- case ItemId.AddToFavorites:
+ case ContextItemId.AddToFavorites:
book.addLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book);
return true;
- case ItemId.RemoveFromFavorites:
+ case ContextItemId.RemoveFromFavorites:
book.removeLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book);
if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) {
getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
}
return true;
- case ItemId.MarkAsRead:
+ case ContextItemId.MarkAsRead:
book.addLabel(Book.READ_LABEL);
myRootTree.Collection.saveBook(book);
getListView().invalidateViews();
return true;
- case ItemId.MarkAsUnread:
+ case ContextItemId.MarkAsUnread:
book.removeLabel(Book.READ_LABEL);
myRootTree.Collection.saveBook(book);
getListView().invalidateViews();
return true;
- case ItemId.DeleteBook:
+ case ContextItemId.DeleteBook:
tryToDeleteBook(book);
return true;
- case ItemId.SyncAgain:
- book.removeLabel(Book.SYNC_FAILURE_LABEL);
- book.removeLabel(Book.SYNC_DELETED_LABEL);
- book.addLabel(Book.SYNC_TOSYNC_LABEL);
- myRootTree.Collection.saveBook(book);
+ case ContextItemId.SyncAgain:
+ syncAgain(book);
if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) {
getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
}
@@ -270,20 +277,39 @@ public class LibraryActivity extends TreeActivity implements MenuIt
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- addMenuItem(menu, 1, "localSearch", R.drawable.ic_menu_search);
- addMenuItem(menu, 2, "rescan", R.drawable.ic_menu_refresh);
+ addMenuItem(menu, OptionsItemId.Search, "localSearch", R.drawable.ic_menu_search);
+ addMenuItem(menu, OptionsItemId.Rescan, "rescan", R.drawable.ic_menu_refresh);
+ addMenuItem(menu, OptionsItemId.SyncAgain, "syncAgain", -1);
+ addMenuItem(menu, OptionsItemId.DeleteAll, "deleteAll", -1);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(2).setEnabled(myRootTree.Collection.status().IsCompleted);
+
+ boolean enableSyncAgain = false;
+ boolean enableDeleteAll = false;
+ final LibraryTree tree = getCurrentTree();
+ if (tree instanceof SyncLabelTree) {
+ final String label = ((SyncLabelTree)tree).Label;
+ if (Book.SYNC_DELETED_LABEL.equals(label)) {
+ enableSyncAgain = true;
+ enableDeleteAll = true;
+ } else if (Book.SYNC_FAILURE_LABEL.equals(label)) {
+ enableSyncAgain = true;
+ }
+ }
+
+ menu.findItem(OptionsItemId.Rescan).setEnabled(myRootTree.Collection.status().IsCompleted);
+ menu.findItem(OptionsItemId.SyncAgain).setVisible(enableSyncAgain);
+ menu.findItem(OptionsItemId.DeleteAll).setVisible(enableDeleteAll);
+
return true;
}
private MenuItem addMenuItem(Menu menu, int id, String resourceKey, int iconId) {
- final String label = LibraryTree.resource().getResource("menu").getResource(resourceKey).getValue();
+ final String label = LibraryTree.resource().getResource(resourceKey).getValue();
final MenuItem item = menu.add(0, id, Menu.NONE, label);
item.setOnMenuItemClickListener(this);
item.setIcon(iconId);
@@ -292,14 +318,32 @@ public class LibraryActivity extends TreeActivity implements MenuIt
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
- case 1:
+ case OptionsItemId.Search:
return onSearchRequested();
- case 2:
+ case OptionsItemId.Rescan:
if (myRootTree.Collection.status().IsCompleted) {
((BookCollectionShadow)myRootTree.Collection).reset(true);
openTree(myRootTree);
}
return true;
+ case OptionsItemId.SyncAgain:
+ for (FBTree tree : getCurrentTree().subtrees()) {
+ if (tree instanceof BookTree) {
+ syncAgain(((BookTree)tree).Book);
+ }
+ }
+ getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
+ return true;
+ case OptionsItemId.DeleteAll:
+ {
+ final List books = new LinkedList();
+ for (FBTree tree : getCurrentTree().subtrees()) {
+ if (tree instanceof BookTree) {
+ books.add(((BookTree)tree).Book);
+ }
+ }
+ tryToDeleteBooks(books);
+ }
default:
return true;
}
@@ -309,37 +353,60 @@ public class LibraryActivity extends TreeActivity implements MenuIt
// Book deletion
//
private class BookDeleter implements DialogInterface.OnClickListener {
- private final Book myBook;
+ private final List myBooks;
- BookDeleter(Book book) {
- myBook = book;
+ BookDeleter(List books) {
+ myBooks = new ArrayList(books);
}
public void onClick(DialogInterface dialog, int which) {
if (getCurrentTree() instanceof FileTree) {
- getListAdapter().remove(new FileTree((FileTree)getCurrentTree(), myBook.File));
+ for (Book book : myBooks) {
+ getListAdapter().remove(new FileTree((FileTree)getCurrentTree(), book.File));
+ myRootTree.Collection.removeBook(book, true);
+ }
getListView().invalidateViews();
- } else if (getCurrentTree().onBookEvent(BookEvent.Removed, myBook)) {
- getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
+ } else {
+ boolean doReplace = false;
+ for (Book book : myBooks) {
+ doReplace |= getCurrentTree().onBookEvent(BookEvent.Removed, book);
+ myRootTree.Collection.removeBook(book, true);
+ }
+ if (doReplace) {
+ getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
+ }
}
-
- myRootTree.Collection.removeBook(myBook, true);
}
}
- private void tryToDeleteBook(Book book) {
+ private void tryToDeleteBooks(List books) {
+ final int size = books.size();
+ if (size == 0) {
+ return;
+ }
final ZLResource dialogResource = ZLResource.resource("dialog");
final ZLResource buttonResource = dialogResource.getResource("button");
- final ZLResource boxResource = dialogResource.getResource("deleteBookBox");
+ final ZLResource boxResource = dialogResource.getResource(
+ size == 1 ? "deleteBookBox" : "deleteMultipleBookBox"
+ );
+ final String title = size == 1
+ ? books.get(0).getTitle()
+ : boxResource.getResource("title").getValue();
+ final String message =
+ boxResource.getResource("message").getValue(size).replaceAll("%s", String.valueOf(size));
new AlertDialog.Builder(this)
- .setTitle(book.getTitle())
- .setMessage(boxResource.getResource("message").getValue())
+ .setTitle(title)
+ .setMessage(message)
.setIcon(0)
- .setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(book))
+ .setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(books))
.setNegativeButton(buttonResource.getResource("no").getValue(), null)
.create().show();
}
+ private void tryToDeleteBook(Book book) {
+ tryToDeleteBooks(Collections.singletonList(book));
+ }
+
private void startBookSearch(final String pattern) {
BookSearchPatternOption.setValue(pattern);
diff --git a/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java b/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java
index a08cda022..828fce009 100644
--- a/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java
+++ b/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java
@@ -216,7 +216,8 @@ public class SynchroniserService extends Service implements IBookCollection.List
return SyncStatus.HashNotComputed;
} else if (myActualHashesFromServer.contains(hash)) {
return SyncStatus.AlreadyUploaded;
- } else if (myDeletedHashesFromServer.contains(hash)) {
+ } else if (myDeletedHashesFromServer.contains(hash) &&
+ !book.labels().contains(Book.SYNC_TOSYNC_LABEL)) {
return SyncStatus.ToBeDeleted;
} else if (book.labels().contains(Book.SYNC_FAILURE_LABEL)) {
return SyncStatus.FailedPreviuousTime;
diff --git a/src/org/geometerplus/fbreader/library/SyncLabelTree.java b/src/org/geometerplus/fbreader/library/SyncLabelTree.java
index b869d6b53..85bc14a26 100644
--- a/src/org/geometerplus/fbreader/library/SyncLabelTree.java
+++ b/src/org/geometerplus/fbreader/library/SyncLabelTree.java
@@ -25,12 +25,12 @@ import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.Filter;
public class SyncLabelTree extends FilteredTree {
- private final String myLabel;
+ public final String Label;
private final ZLResource myResource;
SyncLabelTree(SyncTree parent, String label, Filter filter, ZLResource resource) {
super(parent, filter, -1);
- myLabel = label;
+ Label = label;
myResource = resource;
}
@@ -51,7 +51,7 @@ public class SyncLabelTree extends FilteredTree {
@Override
protected String getStringId() {
- return "@SyncLabelTree " + myLabel;
+ return "@SyncLabelTree " + Label;
}
@Override