package org.ebookdroid.ui.library; import org.ebookdroid.CodecType; import org.ebookdroid.EBookDroidApp; import org.emdev.ui.uimanager.UIManagerAppCompat; import org.sufficientlysecure.viewer.R; import org.ebookdroid.common.cache.CacheManager; import org.ebookdroid.common.cache.CacheManager.ICacheListener; import org.ebookdroid.common.cache.ThumbnailFile; import org.ebookdroid.common.settings.AppSettings; import org.ebookdroid.common.settings.BackupSettings; import org.ebookdroid.common.settings.LibSettings; import org.ebookdroid.common.settings.SettingsManager; import org.ebookdroid.common.settings.books.BookSettings; import org.ebookdroid.common.settings.books.Bookmark; import org.ebookdroid.common.settings.listeners.ILibSettingsChangeListener; import org.ebookdroid.common.settings.listeners.IRecentBooksChangedListener; import org.ebookdroid.ui.library.adapters.BookNode; import org.ebookdroid.ui.library.adapters.BookShelfAdapter; import org.ebookdroid.ui.library.adapters.BooksAdapter; import org.ebookdroid.ui.library.adapters.LibraryAdapter; import org.ebookdroid.ui.library.adapters.RecentAdapter; import org.ebookdroid.ui.library.dialogs.BackupDlg; import org.ebookdroid.ui.library.dialogs.FolderDlg; import org.ebookdroid.ui.library.tasks.CopyBookTask; import org.ebookdroid.ui.library.tasks.MoveBookTask; import org.ebookdroid.ui.library.tasks.RenameBookTask; import org.ebookdroid.ui.opds.OPDSActivity; import org.ebookdroid.ui.settings.SettingsUI; import org.ebookdroid.ui.viewer.ViewerActivity; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import java.io.File; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.emdev.common.backup.BackupManager; import org.emdev.common.filesystem.FileExtensionFilter; import org.emdev.common.filesystem.MediaManager; import org.emdev.common.filesystem.MediaState; import org.emdev.ui.AbstractActivityController; import org.emdev.ui.actions.ActionDialogBuilder; import org.emdev.ui.actions.ActionEx; import org.emdev.ui.actions.ActionMenuHelper; import org.emdev.ui.actions.ActionMethod; import org.emdev.ui.actions.IActionController; import org.emdev.ui.actions.params.Constant; import org.emdev.ui.actions.params.EditableValue; import org.emdev.ui.uimanager.IUIManager; import org.emdev.utils.CompareUtils; import org.emdev.utils.FileUtils; import org.emdev.utils.LengthUtils; public class RecentActivityController extends AbstractActivityController<RecentActivity> implements IBrowserActivity, ILibSettingsChangeListener, IRecentBooksChangedListener, ICacheListener, MediaManager.Listener { public static final AtomicBoolean working = new AtomicBoolean(); private static final int CLEAR_RECENT_LIST = 0; private static final int DELETE_BOOKMARKS = 1; private static final int DELETE_BOOK_SETTINGS = 2; private static final int ERASE_DISK_CACHE = 3; private RecentAdapter recentAdapter; private LibraryAdapter libraryAdapter; private BooksAdapter bookshelfAdapter; private final ThumbnailFile def = CacheManager.getThumbnailFile("."); private boolean recentLoaded = false; public RecentActivityController(final RecentActivity activity) { super(activity, BEFORE_CREATE, AFTER_CREATE, ON_RESUME, ON_DESTROY); working.set(true); } /** * {@inheritDoc} * * @see org.emdev.ui.AbstractActivityController#beforeCreate(android.app.Activity) */ @Override public void beforeCreate(final RecentActivity activity) { super.beforeCreate(activity); recentAdapter = new RecentAdapter(this); bookshelfAdapter = new BooksAdapter(this, recentAdapter); libraryAdapter = new LibraryAdapter(bookshelfAdapter); CacheManager.listeners.addListener(this); MediaManager.listeners.addListener(this); SettingsManager.addListener(this); } /** * {@inheritDoc} * * @see org.emdev.ui.AbstractActivityController#afterCreate(android.app.Activity, boolean) */ @Override public void afterCreate(final RecentActivity activity, final boolean recreated) { final LibSettings libSettings = LibSettings.current(); LibSettings.applySettingsChanges(null, libSettings); final BookSettings recent = SettingsManager.getRecentBook(); if (!recreated) { init(); recentLoaded = checkAutoLoad(libSettings, recent); if (recentLoaded) { return; } EBookDroidApp.checkInstalledFonts(getManagedComponent()); } changeLibraryView(recent != null ? RecentActivity.VIEW_RECENT : RecentActivity.VIEW_LIBRARY); } protected boolean checkAutoLoad(final LibSettings libSettings, final BookSettings recent) { final boolean shouldLoad = AppSettings.current().loadRecent; final File file = (recent != null && recent.fileName != null) ? new File(recent.fileName) : null; final boolean found = file != null ? file.exists() && libSettings.allowedFileTypes.accept(file) : false; if (LCTX.isDebugEnabled()) { LCTX.d("Last book: " + (file != null ? file.getAbsolutePath() : "") + ", found: " + found + ", should load: " + shouldLoad); } if (shouldLoad && found) { changeLibraryView(RecentActivity.VIEW_RECENT); showDocument(Uri.fromFile(file), null); return true; } return false; } protected void init() { final LibSettings libSettings = LibSettings.current(); recentAdapter.setBooks(SettingsManager.getRecentBooks().values(), libSettings.allowedFileTypes); bookshelfAdapter.startScan(); } /** * {@inheritDoc} * * @see org.emdev.ui.AbstractActivityController#onDestroy(boolean) */ @Override public void onDestroy(final boolean finishing) { if (finishing) { if (BackupSettings.current().backupOnExit) { BackupManager.backup(); } working.set(false); bookshelfAdapter.onDestroy(); CacheManager.listeners.removeListener(this); SettingsManager.removeListener(this); MediaManager.listeners.removeListener(this); } } @ActionMethod(ids = R.id.recentmenu_cleanrecent) public void showClearRecentDialog(final ActionEx action) { final ActionDialogBuilder builder = new ActionDialogBuilder(getContext(), this); builder.setTitle(R.string.clear_recent_title); builder.setMultiChoiceItems(R.array.list_clear_recent_mode, R.id.actions_clearRecent); builder.setPositiveButton(R.id.actions_clearRecent); builder.setNegativeButton(); builder.show(); } @ActionMethod(ids = R.id.actions_clearRecent) public void doClearRecent(final ActionEx action) { if (action.isDialogItemSelected(ERASE_DISK_CACHE)) { CacheManager.clear(); recentAdapter.notifyDataSetInvalidated(); libraryAdapter.notifyDataSetInvalidated(); } if (action.isDialogItemSelected(DELETE_BOOK_SETTINGS)) { SettingsManager.deleteAllBookSettings(); recentAdapter.clearBooks(); libraryAdapter.notifyDataSetInvalidated(); } else { if (action.isDialogItemSelected(CLEAR_RECENT_LIST)) { SettingsManager.clearAllRecentBookSettings(); recentAdapter.clearBooks(); libraryAdapter.notifyDataSetInvalidated(); } if (action.isDialogItemSelected(DELETE_BOOKMARKS)) { SettingsManager.deleteAllBookmarks(); } } } @ActionMethod(ids = R.id.bookmenu_removefromrecent) public void removeBookFromRecents(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); if (book != null) { SettingsManager.removeBookFromRecents(book.path); recentAdapter.removeBook(book); libraryAdapter.notifyDataSetInvalidated(); } } @ActionMethod(ids = R.id.bookmenu_cleardata) public void removeCachedBookFiles(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); if (book != null) { CacheManager.clear(book.path); recentAdapter.notifyDataSetInvalidated(); libraryAdapter.notifyDataSetInvalidated(); } } @ActionMethod(ids = R.id.bookmenu_deletesettings) public void removeBookSettings(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); if (book != null) { final BookSettings bs = SettingsManager.getBookSettings(book.path); if (bs != null) { SettingsManager.deleteBookSettings(bs); recentAdapter.removeBook(book); libraryAdapter.notifyDataSetInvalidated(); } } } @ActionMethod(ids = R.id.actions_searchBook) public void searchBook(final ActionEx action) { final Editable value = action.getParameter("input"); final String searchQuery = value.toString(); if (bookshelfAdapter.startSearch(searchQuery)) { if (LibSettings.current().useBookcase) { getManagedComponent().showBookshelf(BooksAdapter.SEARCH_INDEX); } } } @ActionMethod(ids = R.id.mainmenu_settings) public void showSettings(final ActionEx action) { SettingsUI.showAppSettings(getManagedComponent(), null); } @ActionMethod(ids = { R.id.bookmenu_copy, R.id.bookmenu_move }) public void copyBook(final ActionEx action) { final BookNode book = action.getParameter("source"); if (book == null) { return; } final boolean isCopy = action.id == R.id.bookmenu_copy; final int titleId = isCopy ? R.string.copy_book_to_dlg_title : R.string.move_book_to_dlg_title; final int id = isCopy ? R.id.actions_doCopyBook : R.id.actions_doMoveBook; getOrCreateAction(id).putValue("source", book); final FolderDlg dlg = new FolderDlg(this); dlg.show(new File(book.path), titleId, id); } @ActionMethod(ids = R.id.actions_doCopyBook) public void doCopyBook(final ActionEx action) { final File targetFolder = action.getParameter(FolderDlg.SELECTED_FOLDER); final BookNode book = action.getParameter("source"); new CopyBookTask(this.getContext(), recentAdapter, targetFolder).execute(book); } @ActionMethod(ids = R.id.actions_doMoveBook) public void doMoveBook(final ActionEx action) { final File targetFolder = action.getParameter(FolderDlg.SELECTED_FOLDER); final BookNode book = action.getParameter("source"); new MoveBookTask(this.getContext(), recentAdapter, targetFolder).execute(book); } @ActionMethod(ids = R.id.bookmenu_rename) public void renameBook(final ActionEx action) { final BookNode book = action.getParameter("source"); if (book == null) { return; } final FileUtils.FilePath file = FileUtils.parseFilePath(book.path, CodecType.getAllExtensions()); final EditText input = new AppCompatEditText(getManagedComponent()); input.setSingleLine(); input.setText(file.name); input.selectAll(); final ActionDialogBuilder builder = new ActionDialogBuilder(getContext(), this); builder.setTitle(R.string.book_rename_title); builder.setMessage(R.string.book_rename_msg); builder.setView(input); builder.setPositiveButton(R.id.actions_doRenameBook, new Constant("source", book), new Constant("file", file), new EditableValue("input", input)); builder.setNegativeButton().show(); } @ActionMethod(ids = R.id.actions_doRenameBook) public void doRenameBook(final ActionEx action) { final BookNode book = action.getParameter("source"); final FileUtils.FilePath path = action.getParameter("file"); final Editable value = action.getParameter("input"); final String newName = value.toString(); if (!CompareUtils.equals(path.name, newName)) { path.name = newName; new RenameBookTask(this.getContext(), recentAdapter, path).execute(book); } } @ActionMethod(ids = R.id.bookmenu_delete) public void deleteBook(final ActionEx action) { final BookNode book = action.getParameter("source"); if (book == null) { return; } final ActionDialogBuilder builder = new ActionDialogBuilder(getContext(), this); builder.setTitle(R.string.book_delete_title); builder.setMessage(R.string.book_delete_msg); builder.setPositiveButton(R.id.actions_doDeleteBook, new Constant("source", book)); builder.setNegativeButton().show(); } @ActionMethod(ids = R.id.actions_doDeleteBook) public void doDeleteBook(final ActionEx action) { final BookNode book = action.getParameter("source"); if (book == null) { return; } final File f = new File(book.path); if (f.delete()) { CacheManager.clear(book.path); final LibSettings libSettings = LibSettings.current(); recentAdapter.setBooks(SettingsManager.getRecentBooks().values(), libSettings.allowedFileTypes); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.library.IBrowserActivity#setCurrentDir(java.io.File) */ @Override public void setCurrentDir(final File newDir) { } @ActionMethod(ids = { R.id.actions_goToBookmark }) public void openBook(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); final File file = new File(book.path); if (!file.isDirectory()) { final Bookmark b = action.getParameter("bookmark"); showDocument(Uri.fromFile(file), b); } } @ActionMethod(ids = R.id.bookmenu_settings) public void openBookSettings(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); SettingsManager.create(0, book.path, false, null); SettingsUI.showBookSettings(getManagedComponent(), book.path); } @ActionMethod(ids = R.id.bookmenu_openbookshelf) public void openBookShelf(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); final BookShelfAdapter bookShelf = getBookShelf(book); if (bookShelf != null) { final int pos = bookshelfAdapter.getShelfPosition(bookShelf); getManagedComponent().showBookshelf(pos); } } @ActionMethod(ids = R.id.bookmenu_openbookfolder) public void openBookFolder(final ActionEx action) { final BookNode book = action.getParameter(ActionMenuHelper.MENU_ITEM_SOURCE); final Intent myIntent = new Intent(getManagedComponent(), BrowserActivity.class); myIntent.setData(Uri.fromFile(new File(book.path).getParentFile().getAbsoluteFile())); getManagedComponent().startActivity(myIntent); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.library.IBrowserActivity#showDocument(android.net.Uri, * org.ebookdroid.common.settings.books.Bookmark) */ @Override public void showDocument(final Uri uri, final Bookmark b) { final Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.setClass(getManagedComponent(), ViewerActivity.class); if (b != null) { intent.putExtra("pageIndex", "" + b.page.viewIndex); intent.putExtra("offsetX", "" + b.offsetX); intent.putExtra("offsetY", "" + b.offsetY); } getManagedComponent().startActivity(intent); } public void showSelectShelfDlg() { final List<String> names = bookshelfAdapter.getListNames(); if (LengthUtils.isNotEmpty(names)) { final ActionDialogBuilder builder = new ActionDialogBuilder(getContext(), this); builder.setTitle(R.string.bookcase_shelves); builder.setItems(names.toArray(new String[names.size()]), this.getOrCreateAction(R.id.actions_selectShelf)); builder.show(); } } @ActionMethod(ids = R.id.actions_selectShelf) public void selectShelf(final ActionEx action) { final Integer item = action.getParameter(IActionController.DIALOG_ITEM_PROPERTY); getManagedComponent().showBookshelf(item); } @ActionMethod(ids = { R.id.recent_showlibrary, R.id.recent_showrecent }) public void goLibrary(final ActionEx action) { if (!LibSettings.current().useBookcase) { final int viewMode = getManagedComponent().getViewMode(); if (viewMode == RecentActivity.VIEW_RECENT) { changeLibraryView(RecentActivity.VIEW_LIBRARY); } else if (viewMode == RecentActivity.VIEW_LIBRARY) { changeLibraryView(RecentActivity.VIEW_RECENT); } } } @ActionMethod(ids = { R.id.recent_showbrowser, R.id.recent_storage_all, R.id.recent_storage_external, R.id.actions_storage }) public void goFileBrowser(final ActionEx action) { final Intent myIntent = new Intent(getManagedComponent(), BrowserActivity.class); final String path = action.getParameter("path"); if (path != null) { myIntent.setData(Uri.fromFile(new File(path))); } getManagedComponent().startActivity(myIntent); } @ActionMethod(ids = R.id.mainmenu_opds) public void goOPDSBrowser(final ActionEx action) { final Intent myIntent = new Intent(getManagedComponent(), OPDSActivity.class); getManagedComponent().startActivity(myIntent); } @ActionMethod(ids = R.id.recentmenu_backupsettings) public void backupSettings(final ActionEx action) { new BackupDlg(m_managedComponent).show(); } @ActionMethod(ids = R.id.mainmenu_close) public void close(final ActionEx action) { getManagedComponent().finish(); } @Override public void showProgress(final boolean show) { final RecentActivity activity = getManagedComponent(); activity.runOnUiThread(new Runnable() { @Override public void run() { UIManagerAppCompat.setProgressSpinnerVisible(activity, show); } }); } /** * {@inheritDoc} * * @see org.ebookdroid.common.cache.CacheManager.ICacheListener#onThumbnailChanged(org.ebookdroid.common.cache.ThumbnailFile) */ @Override public void onThumbnailChanged(final ThumbnailFile tf) { getManagedComponent().runOnUiThread(new Runnable() { @Override public void run() { final BookNode node = recentAdapter.getNode(tf.book); if (node != null) { recentAdapter.notifyDataSetInvalidated(); final BookShelfAdapter bookShelf = getBookShelf(node); if (bookShelf != null) { bookShelf.notifyDataSetInvalidated(); } } } }); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.library.IBrowserActivity#loadThumbnail(java.lang.String, android.widget.ImageView, int) */ @Override public void loadThumbnail(final String path, final ImageView imageView, final int defaultResID) { final ThumbnailFile newTF = CacheManager.getThumbnailFile(path); imageView.setTag(newTF); final Bitmap defImage = def.getImage(); newTF.loadImageAsync(defImage, new ThumbnailFile.ImageLoadingListener() { @Override public void onImageLoaded(final Bitmap image) { if (image != null && imageView.getTag() == newTF) { imageView.setImageBitmap(image); imageView.postInvalidate(); } } }); } /** * {@inheritDoc} * * @see org.ebookdroid.common.settings.listeners.ILibSettingsChangeListener#onLibSettingsChanged(org.ebookdroid.common.settings.LibSettings, * org.ebookdroid.common.settings.LibSettings, org.ebookdroid.common.settings.LibSettings.Diff) */ @Override public void onLibSettingsChanged(final LibSettings oldSettings, final LibSettings newSettings, final LibSettings.Diff diff) { try { final FileExtensionFilter filter = newSettings.allowedFileTypes; if (diff.isUseBookcaseChanged()) { recentAdapter.setBooks(SettingsManager.getRecentBooks().values(), filter); if (newSettings.useBookcase) { getManagedComponent().showBookcase(bookshelfAdapter, recentAdapter); } else { getManagedComponent().showLibrary(libraryAdapter, recentAdapter); } return; } if (diff.isAutoScanDirsChanged()) { bookshelfAdapter.startScan(); return; } if (diff.isAllowedFileTypesChanged()) { recentAdapter.setBooks(SettingsManager.getRecentBooks().values(), filter); bookshelfAdapter.startScan(); } if (diff.isAutoScanRemovableMediaChanged()) { final Collection<String> media = MediaManager.getReadableMedia(); if (LengthUtils.isNotEmpty(media)) { if (newSettings.autoScanRemovableMedia) { bookshelfAdapter.startScan(media); } else { bookshelfAdapter.removeAll(media); } } } } finally { UIManagerAppCompat.invalidateOptionsMenu(getManagedComponent()); } } /** * {@inheritDoc} * * @see org.ebookdroid.common.settings.listeners.IRecentBooksChangedListener#onRecentBooksChanged() */ @Override public void onRecentBooksChanged() { getManagedComponent().runOnUiThread(new Runnable() { @Override public void run() { final FileExtensionFilter filter = LibSettings.current().allowedFileTypes; recentAdapter.setBooks(SettingsManager.getRecentBooks().values(), filter); } }); } public void changeLibraryView(final int view) { if (!LibSettings.current().useBookcase) { getManagedComponent().changeLibraryView(view); } } public BookShelfAdapter getBookShelf(final BookNode node) { final String parent = new File(node.path).getParentFile().getAbsolutePath(); return bookshelfAdapter.getShelf(parent); } public BookShelfAdapter getBookShelf(final int index) { return bookshelfAdapter.getList(index); } /** * {@inheritDoc} * * @see org.emdev.common.filesystem.MediaManager.Listener#onMediaStateChanged(java.lang.String, * org.emdev.common.filesystem.MediaState, org.emdev.common.filesystem.MediaState) */ @Override public void onMediaStateChanged(final String path, final MediaState oldState, final MediaState newState) { if (newState.readable) { if (oldState == null || !oldState.readable) { if (LibSettings.current().autoScanRemovableMedia) { bookshelfAdapter.startScan(path); } UIManagerAppCompat.invalidateOptionsMenu(getManagedComponent()); } return; } if (oldState != null && oldState.readable) { bookshelfAdapter.removeAll(path); UIManagerAppCompat.invalidateOptionsMenu(getManagedComponent()); } } }