mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-06 03:50:19 +02:00
BookHistory table + new style recent books request
This commit is contained in:
parent
7046eb20c0
commit
3d3e770d9f
8 changed files with 109 additions and 73 deletions
|
@ -181,7 +181,7 @@ public class LibraryService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> recentBooks() {
|
public List<String> recentBooks() {
|
||||||
return SerializerUtil.serializeBookList(myCollection.recentBooks());
|
return recentlyOpenedBooks(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> recentlyOpenedBooks(int count) {
|
public List<String> recentlyOpenedBooks(int count) {
|
||||||
|
|
|
@ -29,7 +29,6 @@ import android.database.Cursor;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.options.Config;
|
import org.geometerplus.zlibrary.core.options.Config;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
|
||||||
import org.geometerplus.zlibrary.core.options.ZLIntegerOption;
|
import org.geometerplus.zlibrary.core.options.ZLIntegerOption;
|
||||||
import org.geometerplus.zlibrary.core.util.RationalNumber;
|
import org.geometerplus.zlibrary.core.util.RationalNumber;
|
||||||
import org.geometerplus.zlibrary.core.util.ZLColor;
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
@ -76,7 +75,7 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
|
|
||||||
private void migrate() {
|
private void migrate() {
|
||||||
final int version = myDatabase.getVersion();
|
final int version = myDatabase.getVersion();
|
||||||
final int currentVersion = 29;
|
final int currentVersion = 30;
|
||||||
if (version >= currentVersion) {
|
if (version >= currentVersion) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +141,8 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
updateTables27();
|
updateTables27();
|
||||||
case 28:
|
case 28:
|
||||||
updateTables28();
|
updateTables28();
|
||||||
|
case 29:
|
||||||
|
updateTables29();
|
||||||
}
|
}
|
||||||
myDatabase.setTransactionSuccessful();
|
myDatabase.setTransactionSuccessful();
|
||||||
myDatabase.setVersion(currentVersion);
|
myDatabase.setVersion(currentVersion);
|
||||||
|
@ -725,30 +726,43 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void saveRecentBookIds(final List<Long> ids) {
|
@Override
|
||||||
|
protected void addBookHistoryEvent(long bookId, int event) {
|
||||||
final SQLiteStatement statement = get(
|
final SQLiteStatement statement = get(
|
||||||
"INSERT OR IGNORE INTO RecentBooks (book_id) VALUES (?)"
|
"INSERT INTO BookHistory (book_id,timestamp,event) VALUES (?,?,?)"
|
||||||
);
|
);
|
||||||
executeAsTransaction(new Runnable() {
|
synchronized (statement) {
|
||||||
public void run() {
|
statement.bindLong(1, bookId);
|
||||||
myDatabase.delete("RecentBooks", null, null);
|
statement.bindLong(2, System.currentTimeMillis());
|
||||||
for (long id : ids) {
|
statement.bindLong(3, event);
|
||||||
statement.bindLong(1, id);
|
statement.executeInsert();
|
||||||
statement.execute();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Long> loadRecentBookIds() {
|
protected void removeBookHistoryEvents(long bookId, int event) {
|
||||||
|
final SQLiteStatement statement = get(
|
||||||
|
"DELETE FROM BookHistory WHERE book_id=? and event=?"
|
||||||
|
);
|
||||||
|
synchronized (statement) {
|
||||||
|
statement.bindLong(1, bookId);
|
||||||
|
statement.bindLong(2, event);
|
||||||
|
statement.executeInsert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Long> loadRecentBookIds(int event, int limit) {
|
||||||
|
System.err.println("REQUESTED: " + event + " LIMIT " + limit);
|
||||||
final Cursor cursor = myDatabase.rawQuery(
|
final Cursor cursor = myDatabase.rawQuery(
|
||||||
"SELECT book_id FROM RecentBooks ORDER BY book_index", null
|
"SELECT book_id FROM BookHistory WHERE event=? GROUP BY book_id ORDER BY timestamp DESC LIMIT ?",
|
||||||
|
new String[] { String.valueOf(event), String.valueOf(limit) }
|
||||||
);
|
);
|
||||||
final LinkedList<Long> ids = new LinkedList<Long>();
|
final LinkedList<Long> ids = new LinkedList<Long>();
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
ids.add(cursor.getLong(0));
|
ids.add(cursor.getLong(0));
|
||||||
}
|
}
|
||||||
|
System.err.println("RESULT: " + ids);
|
||||||
cursor.close();
|
cursor.close();
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
@ -1054,6 +1068,7 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
@Override
|
@Override
|
||||||
protected void deleteBook(long bookId) {
|
protected void deleteBook(long bookId) {
|
||||||
myDatabase.beginTransaction();
|
myDatabase.beginTransaction();
|
||||||
|
myDatabase.execSQL("DELETE FROM BookHistory WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM BookHash WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM BookHash WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM BookAuthor WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM BookAuthor WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM BookLabel WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM BookLabel WHERE book_id=" + bookId);
|
||||||
|
@ -1063,7 +1078,6 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
myDatabase.execSQL("DELETE FROM BookTag WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM BookTag WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM BookUid WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM BookUid WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM Bookmarks WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM Bookmarks WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM RecentBooks WHERE book_id=" + bookId);
|
|
||||||
myDatabase.execSQL("DELETE FROM VisitedHyperlinks WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM VisitedHyperlinks WHERE book_id=" + bookId);
|
||||||
myDatabase.execSQL("DELETE FROM Books WHERE book_id=" + bookId);
|
myDatabase.execSQL("DELETE FROM Books WHERE book_id=" + bookId);
|
||||||
myDatabase.setTransactionSuccessful();
|
myDatabase.setTransactionSuccessful();
|
||||||
|
@ -1165,26 +1179,6 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
"CREATE TABLE IF NOT EXISTS RecentBooks(" +
|
"CREATE TABLE IF NOT EXISTS RecentBooks(" +
|
||||||
"book_index INTEGER PRIMARY KEY," +
|
"book_index INTEGER PRIMARY KEY," +
|
||||||
"book_id INTEGER REFERENCES Books(book_id))");
|
"book_id INTEGER REFERENCES Books(book_id))");
|
||||||
final ArrayList<Long> ids = new ArrayList<Long>();
|
|
||||||
|
|
||||||
final SQLiteStatement statement = myDatabase.compileStatement(
|
|
||||||
"SELECT book_id FROM Books WHERE file_name = ?"
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < 20; ++i) {
|
|
||||||
final ZLStringOption option = new ZLStringOption("LastOpenedBooks", "Book" + i, "");
|
|
||||||
final String fileName = option.getValue();
|
|
||||||
option.setValue("");
|
|
||||||
try {
|
|
||||||
statement.bindString(1, fileName);
|
|
||||||
final long bookId = statement.simpleQueryForLong();
|
|
||||||
if (bookId != -1) {
|
|
||||||
ids.add(bookId);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveRecentBookIds(ids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTables5() {
|
private void updateTables5() {
|
||||||
|
@ -1477,12 +1471,12 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTables26() {
|
private void updateTables26() {
|
||||||
myDatabase.execSQL("DROP TABLE IF EXISTS BookSynchronizationInfo");
|
|
||||||
myDatabase.execSQL(
|
myDatabase.execSQL(
|
||||||
"CREATE TABLE IF NOT EXISTS BookHash(" +
|
"CREATE TABLE IF NOT EXISTS BookHash(" +
|
||||||
"book_id INTEGER PRIMARY KEY REFERENCES Books(book_id)," +
|
"book_id INTEGER PRIMARY KEY REFERENCES Books(book_id)," +
|
||||||
"timestamp INTEGER NOT NULL," +
|
"timestamp INTEGER NOT NULL," +
|
||||||
"hash TEXT(40) NOT NULL)");
|
"hash TEXT(40) NOT NULL)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTables27() {
|
private void updateTables27() {
|
||||||
|
@ -1493,6 +1487,55 @@ final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
myDatabase.execSQL("ALTER TABLE HighlightingStyle ADD COLUMN fg_color INTEGER NOT NULL DEFAULT -1");
|
myDatabase.execSQL("ALTER TABLE HighlightingStyle ADD COLUMN fg_color INTEGER NOT NULL DEFAULT -1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateTables29() {
|
||||||
|
myDatabase.execSQL("DROP TABLE IF EXISTS BookHistory");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE IF NOT EXISTS BookHistory(" +
|
||||||
|
"book_id INTEGER REFERENCES Books(book_id)," +
|
||||||
|
"timestamp INTEGER NOT NULL," +
|
||||||
|
"event INTEGER NOT NULL)"
|
||||||
|
);
|
||||||
|
|
||||||
|
Cursor cursor = myDatabase.rawQuery(
|
||||||
|
"SELECT book_id FROM RecentBooks ORDER BY book_index", null
|
||||||
|
);
|
||||||
|
SQLiteStatement insert = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO BookHistory(book_id,timestamp,event) VALUES (?,?,?)"
|
||||||
|
);
|
||||||
|
insert.bindLong(3, HistoryEvent.Opened);
|
||||||
|
int count = -1;
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
insert.bindLong(1, cursor.getLong(0));
|
||||||
|
insert.bindLong(2, count);
|
||||||
|
insert.executeInsert();
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = myDatabase.rawQuery(
|
||||||
|
"SELECT book_id FROM Books ORDER BY book_id DESC", null
|
||||||
|
);
|
||||||
|
insert = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO BookHistory(book_id,timestamp,event) VALUES (?,?,?)"
|
||||||
|
);
|
||||||
|
insert.bindLong(3, HistoryEvent.Added);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
insert.bindLong(1, cursor.getLong(0));
|
||||||
|
insert.bindLong(2, count);
|
||||||
|
insert.executeInsert();
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = myDatabase.rawQuery(
|
||||||
|
"SELECT book_id,timestamp,event FROM BookHistory", null
|
||||||
|
);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
System.err.println("HISTORY RECORD: " + cursor.getLong(0) + " : " + cursor.getLong(1) + " : " + cursor.getLong(2));
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
private SQLiteStatement get(String sql) {
|
private SQLiteStatement get(String sql) {
|
||||||
SQLiteStatement statement = myStatements.get(sql);
|
SQLiteStatement statement = myStatements.get(sql);
|
||||||
if (statement == null) {
|
if (statement == null) {
|
||||||
|
|
|
@ -59,9 +59,4 @@ public abstract class AbstractBookCollection implements IBookCollection {
|
||||||
public final Book getBookByFile(String path) {
|
public final Book getBookByFile(String path) {
|
||||||
return getBookByFile(ZLFile.createFileByPath(path));
|
return getBookByFile(ZLFile.createFileByPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// deprecated methods
|
|
||||||
public final List<Book> recentBooks() {
|
|
||||||
return recentlyOpenedBooks(12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,6 +506,7 @@ public class Book extends TitledEntity<Book> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean[] result = new boolean[] { true };
|
||||||
database.executeAsTransaction(new Runnable() {
|
database.executeAsTransaction(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (myId >= 0) {
|
if (myId >= 0) {
|
||||||
|
@ -513,11 +514,16 @@ public class Book extends TitledEntity<Book> {
|
||||||
database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle());
|
database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle());
|
||||||
} else {
|
} else {
|
||||||
myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle());
|
myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle());
|
||||||
if (myId != -1 && myVisitedHyperlinks != null) {
|
if (myId == -1) {
|
||||||
|
result[0] = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (myVisitedHyperlinks != null) {
|
||||||
for (String linkId : myVisitedHyperlinks) {
|
for (String linkId : myVisitedHyperlinks) {
|
||||||
database.addVisitedHyperlink(myId, linkId);
|
database.addVisitedHyperlink(myId, linkId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
database.addBookHistoryEvent(myId, BooksDatabase.HistoryEvent.Added);
|
||||||
}
|
}
|
||||||
|
|
||||||
long index = 0;
|
long index = 0;
|
||||||
|
@ -551,8 +557,12 @@ public class Book extends TitledEntity<Book> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
myIsSaved = true;
|
if (result[0]) {
|
||||||
return true;
|
myIsSaved = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> myVisitedHyperlinks;
|
private Set<String> myVisitedHyperlinks;
|
||||||
|
|
|
@ -233,10 +233,6 @@ public class BookCollection extends AbstractBookCollection {
|
||||||
myDuplicateResolver.removeFile(book.File);
|
myDuplicateResolver.removeFile(book.File);
|
||||||
myBooksById.remove(book.getId());
|
myBooksById.remove(book.getId());
|
||||||
|
|
||||||
final List<Long> ids = myDatabase.loadRecentBookIds();
|
|
||||||
if (ids.remove(book.getId())) {
|
|
||||||
myDatabase.saveRecentBookIds(ids);
|
|
||||||
}
|
|
||||||
if (deleteFromDisk) {
|
if (deleteFromDisk) {
|
||||||
book.File.getPhysicalFile().delete();
|
book.File.getPhysicalFile().delete();
|
||||||
}
|
}
|
||||||
|
@ -302,13 +298,11 @@ public class BookCollection extends AbstractBookCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Book> recentlyAddedBooks(int count) {
|
public List<Book> recentlyAddedBooks(int count) {
|
||||||
// TODO: implement
|
return books(myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Added, count));
|
||||||
return books(myDatabase.loadRecentBookIds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Book> recentlyOpenedBooks(int count) {
|
public List<Book> recentlyOpenedBooks(int count) {
|
||||||
// TODO: implement
|
return books(myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Opened, count));
|
||||||
return books(myDatabase.loadRecentBookIds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Book> books(List<Long> ids) {
|
private List<Book> books(List<Long> ids) {
|
||||||
|
@ -404,24 +398,17 @@ public class BookCollection extends AbstractBookCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Book getRecentBook(int index) {
|
public Book getRecentBook(int index) {
|
||||||
final List<Long> recentIds = myDatabase.loadRecentBookIds();
|
final List<Long> recentIds = myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Opened, index + 1);
|
||||||
return recentIds.size() > index ? getBookById(recentIds.get(index)) : null;
|
return recentIds.size() > index ? getBookById(recentIds.get(index)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToRecentlyOpened(Book book) {
|
public void addToRecentlyOpened(Book book) {
|
||||||
final List<Long> ids = myDatabase.loadRecentBookIds();
|
myDatabase.addBookHistoryEvent(book.getId(), BooksDatabase.HistoryEvent.Opened);
|
||||||
final Long bookId = book.getId();
|
|
||||||
ids.remove(bookId);
|
|
||||||
ids.add(0, bookId);
|
|
||||||
if (ids.size() > 12) {
|
|
||||||
ids.remove(12);
|
|
||||||
}
|
|
||||||
myDatabase.saveRecentBookIds(ids);
|
|
||||||
fireBookEvent(BookEvent.Opened, book);
|
fireBookEvent(BookEvent.Opened, book);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeFromRecentlyOpened(Book book) {
|
public void removeFromRecentlyOpened(Book book) {
|
||||||
// TODO: implement
|
myDatabase.removeBookHistoryEvents(book.getId(), BooksDatabase.HistoryEvent.Opened);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStatus(Status status) {
|
private void setStatus(Status status) {
|
||||||
|
|
|
@ -29,6 +29,11 @@ import org.geometerplus.zlibrary.text.view.ZLTextFixedPosition;
|
||||||
import org.geometerplus.zlibrary.text.view.ZLTextPosition;
|
import org.geometerplus.zlibrary.text.view.ZLTextPosition;
|
||||||
|
|
||||||
public abstract class BooksDatabase {
|
public abstract class BooksDatabase {
|
||||||
|
protected interface HistoryEvent {
|
||||||
|
int Added = 0;
|
||||||
|
int Opened = 1;
|
||||||
|
}
|
||||||
|
|
||||||
public static final class NotAvailable extends Exception {
|
public static final class NotAvailable extends Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +94,9 @@ public abstract class BooksDatabase {
|
||||||
protected abstract void removeFileInfo(long fileId);
|
protected abstract void removeFileInfo(long fileId);
|
||||||
protected abstract void saveFileInfo(FileInfo fileInfo);
|
protected abstract void saveFileInfo(FileInfo fileInfo);
|
||||||
|
|
||||||
protected abstract List<Long> loadRecentBookIds();
|
protected abstract void addBookHistoryEvent(long bookId, int event);
|
||||||
protected abstract void saveRecentBookIds(final List<Long> ids);
|
protected abstract void removeBookHistoryEvents(long bookId, int event);
|
||||||
|
protected abstract List<Long> loadRecentBookIds(int event, int limit);
|
||||||
|
|
||||||
protected abstract void setLabel(long bookId, String label);
|
protected abstract void setLabel(long bookId, String label);
|
||||||
protected abstract void removeLabel(long bookId, String label);
|
protected abstract void removeLabel(long bookId, String label);
|
||||||
|
|
|
@ -100,9 +100,4 @@ public interface IBookCollection {
|
||||||
void saveHighlightingStyle(HighlightingStyle style);
|
void saveHighlightingStyle(HighlightingStyle style);
|
||||||
|
|
||||||
void rescan(String path);
|
void rescan(String path);
|
||||||
|
|
||||||
// deprecated methods, kept for compatibility
|
|
||||||
|
|
||||||
// shortcut to recentlyOpenedBooks(12)
|
|
||||||
List<Book> recentBooks();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class RecentBooksTree extends FirstLevelTree {
|
||||||
@Override
|
@Override
|
||||||
public void waitForOpening() {
|
public void waitForOpening() {
|
||||||
clear();
|
clear();
|
||||||
for (Book book : Collection.recentBooks()) {
|
for (Book book : Collection.recentlyOpenedBooks(12)) {
|
||||||
new BookWithAuthorsTree(this, book);
|
new BookWithAuthorsTree(this, book);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue