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

new synchronisation-related actions in library menus

This commit is contained in:
Nikolay Pultsin 2014-07-27 22:10:55 +01:00
parent 0a7aa5fc29
commit 05fd7f181f
4 changed files with 126 additions and 54 deletions

View file

@ -53,10 +53,8 @@
<node name="fileTreeLibrary" value="FBReader library"> <node name="fileTreeLibrary" value="FBReader library">
<node name="summary" value="FBReader books directory"/> <node name="summary" value="FBReader books directory"/>
</node> </node>
<node name="menu"> <node name="localSearch" value="Search"/>
<node name="localSearch" value="Search"/> <node name="rescan" value="Rescan"/>
<node name="rescan" value="Rescan"/>
</node>
<node name="openBook" value="Open book"/> <node name="openBook" value="Open book"/>
<node name="showBookInfo" value="Book info"/> <node name="showBookInfo" value="Book info"/>
<node name="shareBook" value="Share book"/> <node name="shareBook" value="Share book"/>
@ -66,6 +64,8 @@
<node name="removeFromRecents" value="Remove from recent list"/> <node name="removeFromRecents" value="Remove from recent list"/>
<node name="markAsRead" value="Mark as read"/> <node name="markAsRead" value="Mark as read"/>
<node name="markAsUnread" value="Mark as unread"/> <node name="markAsUnread" value="Mark as unread"/>
<node name="deleteAll" value="Delete all"/>
<node name="syncAgain" value="Synchronise again"/>
</node> </node>
<node name="networkLibrary" value="FBReader network library"> <node name="networkLibrary" value="FBReader network library">
<node name="byAuthor" value="By author"> <node name="byAuthor" value="By author">
@ -849,6 +849,10 @@
<node name="deleteBookBox"> <node name="deleteBookBox">
<node name="message" value="The book file will be removed irreversibly. Are you sure?"/> <node name="message" value="The book file will be removed irreversibly. Are you sure?"/>
</node> </node>
<node name="deleteMultipleBookBox">
<node name="title" value="Delete books"/>
<node name="message" value="%s book files will be removed irreversibly. Are you sure?"/>
</node>
<node name="redownloadFileBox"> <node name="redownloadFileBox">
<node name="message" value="File already exists. Redownload?"/> <node name="message" value="File already exists. Redownload?"/>
</node> </node>

View file

@ -19,7 +19,7 @@
package org.geometerplus.android.fbreader.library; package org.geometerplus.android.fbreader.library;
import java.util.List; import java.util.*;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.SearchManager; import android.app.SearchManager;
@ -154,10 +154,7 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
return true; return true;
} }
// private interface ContextItemId {
// Context menu
//
private interface ItemId {
int OpenBook = 0; int OpenBook = 0;
int ShowBookInfo = 1; int ShowBookInfo = 1;
int ShareBook = 2; int ShareBook = 2;
@ -168,6 +165,12 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
int DeleteBook = 7; int DeleteBook = 7;
int SyncAgain = 8; int SyncAgain = 8;
} }
private interface OptionsItemId {
int Search = 0;
int Rescan = 1;
int SyncAgain = 2;
int DeleteAll = 3;
}
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
@ -182,26 +185,26 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
final ZLResource resource = LibraryTree.resource(); final ZLResource resource = LibraryTree.resource();
final List<String> labels = book.labels(); final List<String> labels = book.labels();
menu.setHeaderTitle(book.getTitle()); menu.setHeaderTitle(book.getTitle());
menu.add(0, ItemId.OpenBook, 0, resource.getResource("openBook").getValue()); menu.add(0, ContextItemId.OpenBook, 0, resource.getResource("openBook").getValue());
menu.add(0, ItemId.ShowBookInfo, 0, resource.getResource("showBookInfo").getValue()); menu.add(0, ContextItemId.ShowBookInfo, 0, resource.getResource("showBookInfo").getValue());
if (book.File.getPhysicalFile() != null) { 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)) { 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 { } 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)) { 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 { } 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)) { 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)) { 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<LibraryTree> implements MenuIt
return super.onContextItemSelected(item); 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) { private boolean onContextItemSelected(int itemId, Book book) {
switch (itemId) { switch (itemId) {
case ItemId.OpenBook: case ContextItemId.OpenBook:
FBReader.openBookActivity(this, book, null); FBReader.openBookActivity(this, book, null);
return true; return true;
case ItemId.ShowBookInfo: case ContextItemId.ShowBookInfo:
showBookInfo(book); showBookInfo(book);
return true; return true;
case ItemId.ShareBook: case ContextItemId.ShareBook:
FBUtil.shareBook(this, book); FBUtil.shareBook(this, book);
return true; return true;
case ItemId.AddToFavorites: case ContextItemId.AddToFavorites:
book.addLabel(Book.FAVORITE_LABEL); book.addLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book); myRootTree.Collection.saveBook(book);
return true; return true;
case ItemId.RemoveFromFavorites: case ContextItemId.RemoveFromFavorites:
book.removeLabel(Book.FAVORITE_LABEL); book.removeLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book); myRootTree.Collection.saveBook(book);
if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) { if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) {
getListAdapter().replaceAll(getCurrentTree().subtrees(), true); getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
} }
return true; return true;
case ItemId.MarkAsRead: case ContextItemId.MarkAsRead:
book.addLabel(Book.READ_LABEL); book.addLabel(Book.READ_LABEL);
myRootTree.Collection.saveBook(book); myRootTree.Collection.saveBook(book);
getListView().invalidateViews(); getListView().invalidateViews();
return true; return true;
case ItemId.MarkAsUnread: case ContextItemId.MarkAsUnread:
book.removeLabel(Book.READ_LABEL); book.removeLabel(Book.READ_LABEL);
myRootTree.Collection.saveBook(book); myRootTree.Collection.saveBook(book);
getListView().invalidateViews(); getListView().invalidateViews();
return true; return true;
case ItemId.DeleteBook: case ContextItemId.DeleteBook:
tryToDeleteBook(book); tryToDeleteBook(book);
return true; return true;
case ItemId.SyncAgain: case ContextItemId.SyncAgain:
book.removeLabel(Book.SYNC_FAILURE_LABEL); syncAgain(book);
book.removeLabel(Book.SYNC_DELETED_LABEL);
book.addLabel(Book.SYNC_TOSYNC_LABEL);
myRootTree.Collection.saveBook(book);
if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) { if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) {
getListAdapter().replaceAll(getCurrentTree().subtrees(), true); getListAdapter().replaceAll(getCurrentTree().subtrees(), true);
} }
@ -270,20 +277,39 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
addMenuItem(menu, 1, "localSearch", R.drawable.ic_menu_search); addMenuItem(menu, OptionsItemId.Search, "localSearch", R.drawable.ic_menu_search);
addMenuItem(menu, 2, "rescan", R.drawable.ic_menu_refresh); addMenuItem(menu, OptionsItemId.Rescan, "rescan", R.drawable.ic_menu_refresh);
addMenuItem(menu, OptionsItemId.SyncAgain, "syncAgain", -1);
addMenuItem(menu, OptionsItemId.DeleteAll, "deleteAll", -1);
return true; return true;
} }
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(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; return true;
} }
private MenuItem addMenuItem(Menu menu, int id, String resourceKey, int iconId) { 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); final MenuItem item = menu.add(0, id, Menu.NONE, label);
item.setOnMenuItemClickListener(this); item.setOnMenuItemClickListener(this);
item.setIcon(iconId); item.setIcon(iconId);
@ -292,14 +318,32 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case 1: case OptionsItemId.Search:
return onSearchRequested(); return onSearchRequested();
case 2: case OptionsItemId.Rescan:
if (myRootTree.Collection.status().IsCompleted) { if (myRootTree.Collection.status().IsCompleted) {
((BookCollectionShadow)myRootTree.Collection).reset(true); ((BookCollectionShadow)myRootTree.Collection).reset(true);
openTree(myRootTree); openTree(myRootTree);
} }
return true; 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<Book> books = new LinkedList<Book>();
for (FBTree tree : getCurrentTree().subtrees()) {
if (tree instanceof BookTree) {
books.add(((BookTree)tree).Book);
}
}
tryToDeleteBooks(books);
}
default: default:
return true; return true;
} }
@ -309,37 +353,60 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
// Book deletion // Book deletion
// //
private class BookDeleter implements DialogInterface.OnClickListener { private class BookDeleter implements DialogInterface.OnClickListener {
private final Book myBook; private final List<Book> myBooks;
BookDeleter(Book book) { BookDeleter(List<Book> books) {
myBook = book; myBooks = new ArrayList<Book>(books);
} }
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (getCurrentTree() instanceof FileTree) { 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(); getListView().invalidateViews();
} else if (getCurrentTree().onBookEvent(BookEvent.Removed, myBook)) { } else {
getListAdapter().replaceAll(getCurrentTree().subtrees(), true); 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<Book> books) {
final int size = books.size();
if (size == 0) {
return;
}
final ZLResource dialogResource = ZLResource.resource("dialog"); final ZLResource dialogResource = ZLResource.resource("dialog");
final ZLResource buttonResource = dialogResource.getResource("button"); 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) new AlertDialog.Builder(this)
.setTitle(book.getTitle()) .setTitle(title)
.setMessage(boxResource.getResource("message").getValue()) .setMessage(message)
.setIcon(0) .setIcon(0)
.setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(book)) .setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(books))
.setNegativeButton(buttonResource.getResource("no").getValue(), null) .setNegativeButton(buttonResource.getResource("no").getValue(), null)
.create().show(); .create().show();
} }
private void tryToDeleteBook(Book book) {
tryToDeleteBooks(Collections.singletonList(book));
}
private void startBookSearch(final String pattern) { private void startBookSearch(final String pattern) {
BookSearchPatternOption.setValue(pattern); BookSearchPatternOption.setValue(pattern);

View file

@ -216,7 +216,8 @@ public class SynchroniserService extends Service implements IBookCollection.List
return SyncStatus.HashNotComputed; return SyncStatus.HashNotComputed;
} else if (myActualHashesFromServer.contains(hash)) { } else if (myActualHashesFromServer.contains(hash)) {
return SyncStatus.AlreadyUploaded; return SyncStatus.AlreadyUploaded;
} else if (myDeletedHashesFromServer.contains(hash)) { } else if (myDeletedHashesFromServer.contains(hash) &&
!book.labels().contains(Book.SYNC_TOSYNC_LABEL)) {
return SyncStatus.ToBeDeleted; return SyncStatus.ToBeDeleted;
} else if (book.labels().contains(Book.SYNC_FAILURE_LABEL)) { } else if (book.labels().contains(Book.SYNC_FAILURE_LABEL)) {
return SyncStatus.FailedPreviuousTime; return SyncStatus.FailedPreviuousTime;

View file

@ -25,12 +25,12 @@ import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.Filter; import org.geometerplus.fbreader.book.Filter;
public class SyncLabelTree extends FilteredTree { public class SyncLabelTree extends FilteredTree {
private final String myLabel; public final String Label;
private final ZLResource myResource; private final ZLResource myResource;
SyncLabelTree(SyncTree parent, String label, Filter filter, ZLResource resource) { SyncLabelTree(SyncTree parent, String label, Filter filter, ZLResource resource) {
super(parent, filter, -1); super(parent, filter, -1);
myLabel = label; Label = label;
myResource = resource; myResource = resource;
} }
@ -51,7 +51,7 @@ public class SyncLabelTree extends FilteredTree {
@Override @Override
protected String getStringId() { protected String getStringId() {
return "@SyncLabelTree " + myLabel; return "@SyncLabelTree " + Label;
} }
@Override @Override