Migrate from to new Model for BookDatabaseEntity

This commit is contained in:
Sean Mac Gillicuddy 2019-05-15 13:21:11 +01:00
parent 0503d7272b
commit 5b01c30a51
19 changed files with 193 additions and 176 deletions

View File

@ -9,20 +9,16 @@ import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.widget.Button;
import android.widget.CheckBox;
import java.util.List;
import org.kiwix.kiwixmobile.base.BaseActivity;
import org.kiwix.kiwixmobile.database.BookDao;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import java.io.File;
import java.util.ArrayList;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import java.io.File;
import java.util.List;
import javax.inject.Inject;
import org.kiwix.kiwixmobile.base.BaseActivity;
import org.kiwix.kiwixmobile.database.BookDao;
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import static org.kiwix.kiwixmobile.utils.LanguageUtils.getCurrentLocale;
@ -90,10 +86,11 @@ public class KiwixErrorActivity extends BaseActivity {
}
if(allowZimsCheckbox.isChecked()) {
List<LibraryNetworkEntity.Book> books = bookDao.getBooks();
List<BookOnDisk> books = bookDao.getBooks();
StringBuilder sb = new StringBuilder();
for(LibraryNetworkEntity.Book book: books) {
for (BookOnDisk bookOnDisk : books) {
final LibraryNetworkEntity.Book book = bookOnDisk.getBook();
String bookString = book.getTitle() +
":\nArticles: ["+ book.getArticleCount() +
"]\nCreator: [" + book.getCreator() +

View File

@ -24,9 +24,12 @@ import io.reactivex.Flowable;
import io.reactivex.processors.BehaviorProcessor;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import org.kiwix.kiwixmobile.database.entity.BookDatabaseEntity;
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.hasParts;
@ -36,7 +39,7 @@ import static org.kiwix.kiwixmobile.downloader.ChunkUtils.hasParts;
*/
public class BookDao extends BaseDao {
private final BehaviorProcessor<List<Book>> booksProcessor = BehaviorProcessor.create();
private final BehaviorProcessor<List<BookOnDisk>> booksProcessor = BehaviorProcessor.create();
@Inject
public BookDao(KiwixDatabase kiwixDatabase) {
@ -48,61 +51,49 @@ public class BookDao extends BaseDao {
booksProcessor.onNext(getBooks());
}
public Flowable<List<Book>> books() {
public Flowable<List<BookOnDisk>> books() {
return booksProcessor;
}
public void setBookDetails(Book book, SquidCursor<BookDatabaseEntity> bookCursor) {
book.databaseId = bookCursor.get(BookDatabaseEntity.ID);
book.id = bookCursor.get(BookDatabaseEntity.BOOK_ID);
book.title = bookCursor.get(BookDatabaseEntity.TITLE);
book.description = bookCursor.get(BookDatabaseEntity.DESCRIPTION);
book.language = bookCursor.get(BookDatabaseEntity.LANGUAGE);
book.creator = bookCursor.get(BookDatabaseEntity.BOOK_CREATOR);
book.publisher = bookCursor.get(BookDatabaseEntity.PUBLISHER);
book.date = bookCursor.get(BookDatabaseEntity.DATE);
book.file = new File(bookCursor.get(BookDatabaseEntity.URL));
book.articleCount = bookCursor.get(BookDatabaseEntity.ARTICLE_COUNT);
book.mediaCount = bookCursor.get(BookDatabaseEntity.MEDIA_COUNT);
book.size = bookCursor.get(BookDatabaseEntity.SIZE);
book.favicon = bookCursor.get(BookDatabaseEntity.FAVICON);
book.bookName = bookCursor.get(BookDatabaseEntity.NAME);
}
public void setBookDatabaseEntity(Book book, BookDatabaseEntity bookDatabaseEntity) {
final String path = book.file.getPath();
bookDatabaseEntity.setBookId(book.getId())
public void setBookDatabaseEntity(BookOnDisk bookonDisk, BookDatabaseEntity bookDatabaseEntity) {
final Book book = bookonDisk.getBook();
bookDatabaseEntity
.setFilePath(bookonDisk.getFile().getPath())
.setBookId(book.getId())
.setTitle(book.getTitle())
.setDescription(book.getDescription())
.setLanguage(book.getLanguage())
.setBookCreator(book.getCreator())
.setPublisher(book.getPublisher())
.setDate(book.getDate())
.setUrl(path)
.setUrl(book.getUrl())
.setArticleCount(book.getArticleCount())
.setMediaCount(book.getMediaCount())
.setSize(book.getSize())
.setFavicon(book.getFavicon())
.setName(book.getName());
kiwixDatabase.deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(path));
kiwixDatabase.persistWithOnConflict(bookDatabaseEntity, TableStatement.ConflictAlgorithm.REPLACE);
.setName(book.getName())
.setFavicon(book.getFavicon());
}
public List<Book> getBooks() {
public List<BookOnDisk> getBooks() {
kiwixDatabase.beginTransaction();
ArrayList<Book> books = new ArrayList<>();
ArrayList<BookOnDisk> books = new ArrayList<>();
final BookDatabaseEntity bookDatabaseEntity = new BookDatabaseEntity();
try(SquidCursor<BookDatabaseEntity> bookCursor = kiwixDatabase.query(
BookDatabaseEntity.class,
Query.select())) {
while (bookCursor.moveToNext()) {
Book book = new Book();
setBookDetails(book, bookCursor);
if (!hasParts(book.file)) {
if (book.file.exists()) {
bookDatabaseEntity.readPropertiesFromCursor(bookCursor);
final File file = new File(bookDatabaseEntity.getFilePath());
BookOnDisk book = new BookOnDisk(
bookDatabaseEntity.getId(),
toBook(bookDatabaseEntity),
file);
if (!hasParts(file)) {
if (file.exists()) {
books.add(book);
} else {
kiwixDatabase.deleteWhere(BookDatabaseEntity.class,
BookDatabaseEntity.URL.eq(book.file));
BookDatabaseEntity.FILE_PATH.eq(file.getPath()));
}
}
}
@ -112,19 +103,41 @@ public class BookDao extends BaseDao {
return books;
}
public void saveBooks(List<Book> books) {
public void saveBooks(Collection<BookOnDisk> books) {
kiwixDatabase.beginTransaction();
for (Book book : books) {
for (BookOnDisk book : books) {
if (book != null) {
BookDatabaseEntity bookDatabaseEntity = new BookDatabaseEntity();
setBookDatabaseEntity(book, bookDatabaseEntity);
kiwixDatabase.deleteWhere(BookDatabaseEntity.class,
BookDatabaseEntity.FILE_PATH.eq(bookDatabaseEntity.getFilePath()));
kiwixDatabase.persistWithOnConflict(bookDatabaseEntity,
TableStatement.ConflictAlgorithm.REPLACE);
}
}
kiwixDatabase.setTransactionSuccessful();
kiwixDatabase.endTransaction();
}
public void deleteBook(String id) {
kiwixDatabase.deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.BOOK_ID.eq(id));
public void deleteBook(Long id) {
kiwixDatabase.deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.ID.eq(id));
}
private LibraryNetworkEntity.Book toBook(BookDatabaseEntity bookDatabaseEntity) {
final LibraryNetworkEntity.Book book = new LibraryNetworkEntity.Book();
book.id = bookDatabaseEntity.getBookId();
book.title = bookDatabaseEntity.getTitle();
book.description = bookDatabaseEntity.getDescription();
book.language = bookDatabaseEntity.getLanguage();
book.creator = bookDatabaseEntity.getBookCreator();
book.publisher = bookDatabaseEntity.getPublisher();
book.date = bookDatabaseEntity.getDate();
book.url = bookDatabaseEntity.getUrl();
book.articleCount = bookDatabaseEntity.getArticleCount();
book.mediaCount = bookDatabaseEntity.getMediaCount();
book.size = bookDatabaseEntity.getSize();
book.bookName = bookDatabaseEntity.getName();
book.favicon = bookDatabaseEntity.getFavicon();
return book;
}
}

View File

@ -23,12 +23,9 @@ import com.yahoo.squidb.sql.Query;
import com.yahoo.squidb.sql.TableStatement;
import io.reactivex.Flowable;
import io.reactivex.processors.BehaviorProcessor;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import kotlin.collections.ArraysKt;
import org.jetbrains.annotations.NotNull;
import org.kiwix.kiwixmobile.database.entity.DownloadDatabaseEntity;
import org.kiwix.kiwixmobile.downloader.model.DownloadModel;
@ -98,7 +95,7 @@ public class DownloadDao extends BaseDao {
.setFavIcon(book.getFavicon());
}
private List<DownloadModel> getDownloads() {
public List<DownloadModel> getDownloads() {
return toList(kiwixDatabase.query(DownloadDatabaseEntity.class, Query.select()));
}
@ -126,7 +123,6 @@ public class DownloadDao extends BaseDao {
book.publisher = downloadDatabaseEntity.getPublisher();
book.date = downloadDatabaseEntity.getDate();
book.url = downloadDatabaseEntity.getUrl();
book.file = new File(downloadDatabaseEntity.getUrl());
book.articleCount = downloadDatabaseEntity.getArticleCount();
book.mediaCount = downloadDatabaseEntity.getMediaCount();
book.size = downloadDatabaseEntity.getSize();

View File

@ -118,7 +118,7 @@ public class KiwixDatabase extends SquidDatabase {
tryCreateTable(RecentSearch.TABLE);
}
if (newVersion >= 12) {
tryAddColumn(BookDatabaseEntity.REMOTE_URL);
//tryAddColumn(BookDatabaseEntity.REMOTE_URL);
}
if (newVersion >= 13) {
tryAddColumn(BookDatabaseEntity.NAME);

View File

@ -24,6 +24,8 @@ import com.yahoo.squidb.annotations.TableModelSpec;
@TableModelSpec(className = "BookDatabaseEntity", tableName = "book")
public class BookDataSource {
public String filePath;
public String bookId;
public String title;
@ -39,9 +41,6 @@ public class BookDataSource {
public String date;
public String url;
public String remoteUrl;
public String articleCount;
public String mediaCount;
@ -52,6 +51,5 @@ public class BookDataSource {
public String name;
public boolean downloaded;
}

View File

@ -17,13 +17,10 @@
*/
package org.kiwix.kiwixmobile.downloader;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.StorageUtils;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import org.kiwix.kiwixmobile.utils.StorageUtils;
public class ChunkUtils {
@ -80,14 +77,14 @@ public class ChunkUtils {
}
}
public static long getCurrentSize(LibraryNetworkEntity.Book book) {
long size = 0;
File[] files = getAllZimParts(book.file);
for (File file : files) {
size += file.length();
}
return size;
}
//public static long getCurrentSize(LibraryNetworkEntity.Book book) {
// long size = 0;
// File[] files = getAllZimParts(book.file);
// for (File file : files) {
// size += file.length();
// }
// return size;
//}
private static File[] getAllZimParts(File file) {
final String baseName = baseNameFromParts(file);

View File

@ -79,7 +79,7 @@ class DownloadManagerRequester @Inject constructor(
Uri.fromFile(
File(
"${sharedPreferenceUtil.prefStorage}/Kiwix/${
StorageUtils.getFileNameFromUrl(uri.toString())
StorageUtils.getFileNameFromUrl(urlString)
}"
)
)

View File

@ -61,14 +61,10 @@ import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil;
import org.kiwix.kiwixmobile.utils.StorageUtils;
import org.kiwix.kiwixmobile.utils.TestingUtils;
import org.kiwix.kiwixmobile.zim_manager.ZimManageActivity;
import org.kiwix.kiwixmobile.zim_manager.library_view.LibraryFragment;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.completeChunk;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.completeDownload;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.deleteAllParts;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.getCurrentSize;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.initialChunk;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.isPresent;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_BOOK;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_LIBRARY;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_NOTIFICATION_ID;
@ -186,7 +182,7 @@ public class DownloadService extends Service {
NotificationCompat.Action pause = new NotificationCompat.Action(R.drawable.ic_pause_black_24dp, getString(R.string.download_pause), pausePending);
NotificationCompat.Action stop = new NotificationCompat.Action(R.drawable.ic_stop_black_24dp, getString(R.string.download_stop), stopPending);
if(flags == START_FLAG_REDELIVERY && book.file == null) {
if (flags == START_FLAG_REDELIVERY /*&& book.file == null*/) {
return START_NOT_STICKY;
} else {
notification.put(notificationID , new NotificationCompat.Builder(this, ONGOING_DOWNLOAD_CHANNEL_ID)
@ -288,13 +284,13 @@ public class DownloadService extends Service {
// KIWIX_ROOT + StorageUtils.getFileNameFromUrl(book.getUrl()));
//}
TestingUtils.bindResource(DownloadService.class);
if (book.file != null && isPresent(book.file.getPath())) {
// Calculate initial download progress
int initial = (int) (getCurrentSize(book) / (Long.valueOf(book.getSize()) * BOOK_SIZE_OFFSET));
notification.get(notificationID).setProgress(100, initial, false);
updateDownloadFragmentProgress(initial, notificationID, book);
notificationManager.notify(notificationID, notification.get(notificationID).build());
}
//if (book.file != null && isPresent(book.file.getPath())) {
// // Calculate initial download progress
// int initial = (int) (getCurrentSize(book) / (Long.valueOf(book.getSize()) * BOOK_SIZE_OFFSET));
// notification.get(notificationID).setProgress(100, initial, false);
// updateDownloadFragmentProgress(initial, notificationID, book);
// notificationManager.notify(notificationID, notification.get(notificationID).build());
//}
kiwixService.getMetaLinks(url)
.retryWhen(errors -> errors.flatMap(error -> Observable.timer(5, TimeUnit.SECONDS)))
.subscribeOn(AndroidSchedulers.mainThread())
@ -307,14 +303,14 @@ public class DownloadService extends Service {
notification.get(notificationID).setContentText(getString(R.string.zim_file_downloaded));
final Intent target = new Intent(this, KiwixMobileActivity.class);
target.putExtra(EXTRA_ZIM_FILE, KIWIX_ROOT + StorageUtils.getFileNameFromUrl(book.getUrl()));
File filec = book.file;
completeDownload(filec);
//File filec = book.file;
//completeDownload(filec);
target.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
PendingIntent pendingIntent = PendingIntent.getActivity
(getBaseContext(), 0,
target, PendingIntent.FLAG_CANCEL_CURRENT);
book.downloaded = true;
bookDao.deleteBook(book.id);
//book.downloaded = true;
//bookDao.deleteBook(book.id);
notification.get(notificationID).setContentIntent(pendingIntent);
// notification.get(notificationID).mActions.clear();
TestingUtils.unbindResource(DownloadService.class);

View File

@ -0,0 +1,10 @@
package org.kiwix.kiwixmobile.downloader.model
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
import java.io.File
data class BookOnDisk(
val databaseId: Long? = null,
val book: Book,
val file: File
)

View File

@ -22,16 +22,18 @@ import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity
import org.kiwix.kiwixmobile.library.entity.MetaLinkNetworkEntity
data class DownloadRequest(
val uri: Uri,
val urlString: String,
val title: String,
val description: String
) {
val uri get() = Uri.parse(urlString)
constructor(
metaLinkNetworkEntity: MetaLinkNetworkEntity,
book: LibraryNetworkEntity.Book
) : this(
Uri.parse(metaLinkNetworkEntity.relevantUrl.value),
metaLinkNetworkEntity.relevantUrl.value,
book.title,
book.description
)

View File

@ -68,9 +68,8 @@ class DownloadStatus(
val uri: String?,
val book: Book
) {
fun toBook() = book.also {
book.file = File(Uri.parse(localUri).path)
}
fun toBookOnDisk() = BookOnDisk(book = book, file = File(Uri.parse(localUri).path))
constructor(
cursor: Cursor,

View File

@ -18,7 +18,6 @@
*/
package org.kiwix.kiwixmobile.library.entity;
import java.io.File;
import java.io.Serializable;
import java.util.LinkedList;
import org.simpleframework.xml.Attribute;
@ -44,9 +43,6 @@ public class LibraryNetworkEntity {
@Root(name = "book", strict = false)
public static class Book implements Serializable{
@Attribute(name = "databaseId", required = false)
public long databaseId;
@Attribute(name = "id", required = false)
public String id;
@ -92,12 +88,8 @@ public class LibraryNetworkEntity {
@Attribute(name = "tags", required = false)
public String tags;
public boolean downloaded = false;
public int searchMatches = 0;
public File file;
public String getId() {
return this.id;
}

View File

@ -26,18 +26,19 @@ import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import java.util.ArrayList;
import org.kiwix.kiwixmobile.ZimContentProvider;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Collection;
import java.util.Vector;
import eu.mhutti1.utils.storage.StorageDevice;
import eu.mhutti1.utils.storage.StorageDeviceUtils;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import org.kiwix.kiwixmobile.ZimContentProvider;
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk;
import org.kiwix.kiwixmobile.downloader.model.DownloadModel;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.StorageUtils;
import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
@ -48,13 +49,15 @@ public class FileSearch {
private final Context context;
private final List<DownloadModel> downloads;
private final ResultListener listener;
private boolean fileSystemScanCompleted = false;
private boolean mediaStoreScanCompleted = false;
public FileSearch(Context ctx, ResultListener listener) {
public FileSearch(Context ctx, List<DownloadModel> downloads, ResultListener listener) {
this.context = ctx;
this.downloads = downloads;
this.listener = listener;
}
@ -96,7 +99,6 @@ public class FileSearch {
try {
while (query.moveToNext()) {
File file = new File(query.getString(0));
if (file.canRead())
onFileFound(file.getAbsolutePath());
}
@ -174,7 +176,7 @@ public class FileSearch {
return files.toArray(arr);
}
public static synchronized LibraryNetworkEntity.Book fileToBook(String filePath) {
public static synchronized BookOnDisk fileToBookOnDisk(String filePath) {
LibraryNetworkEntity.Book book = null;
if (ZimContentProvider.zimFileName != null) {
@ -188,7 +190,6 @@ public class FileSearch {
book = new LibraryNetworkEntity.Book();
book.title = ZimContentProvider.getZimFileTitle();
book.id = ZimContentProvider.getId();
book.file = new File(filePath);
book.size = String.valueOf(ZimContentProvider.getFileSize());
book.favicon = ZimContentProvider.getFavicon();
book.creator = ZimContentProvider.getCreator();
@ -210,7 +211,7 @@ public class FileSearch {
}
ZimContentProvider.originalFileName = "";
return book;
return new BookOnDisk(null, book, new File(filePath));
}
// Fill fileList with files found in the specific directory
@ -225,14 +226,26 @@ public class FileSearch {
// Callback that a new file has been found
public void onFileFound(String filePath) {
LibraryNetworkEntity.Book book = fileToBook(filePath);
if (fileIsDownloading(filePath)) {
return;
}
BookOnDisk book = fileToBookOnDisk(filePath);
if (book != null)
listener.onBookFound(book);
}
private boolean fileIsDownloading(String filePath) {
for (DownloadModel download : downloads) {
if (filePath.endsWith(StorageUtils.getFileNameFromUrl(download.getBook().getUrl()))) {
return true;
}
}
return false;
}
public interface ResultListener {
void onBookFound(LibraryNetworkEntity.Book book);
void onBookFound(BookOnDisk book);
void onScanCompleted();
}

View File

@ -34,6 +34,7 @@ import org.kiwix.kiwixmobile.database.BookDao
import org.kiwix.kiwixmobile.database.DownloadDao
import org.kiwix.kiwixmobile.database.NetworkLanguageDao
import org.kiwix.kiwixmobile.downloader.Downloader
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk
import org.kiwix.kiwixmobile.downloader.model.DownloadItem
import org.kiwix.kiwixmobile.downloader.model.DownloadModel
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Successful
@ -75,7 +76,7 @@ class ZimManageViewModel @Inject constructor(
val libraryItems: MutableLiveData<List<LibraryListItem>> = MutableLiveData()
val downloadItems: MutableLiveData<List<DownloadItem>> = MutableLiveData()
val bookItems: MutableLiveData<List<Book>> = MutableLiveData()
val bookItems: MutableLiveData<List<BookOnDisk>> = MutableLiveData()
val deviceListIsRefreshing = MutableLiveData<Boolean>()
val libraryListIsRefreshing = MutableLiveData<Boolean>()
val networkStates = MutableLiveData<NetworkState>()
@ -102,7 +103,7 @@ class ZimManageViewModel @Inject constructor(
private fun disposables(): Array<Disposable> {
val downloads: Flowable<MutableList<DownloadModel>> = downloadDao.downloads()
val downloadStatuses = downloadStatuses(downloads)
val booksFromDao: Flowable<List<Book>> = books()
val booksFromDao = books()
val networkLibrary = PublishProcessor.create<LibraryNetworkEntity>()
return arrayOf(
updateDownloadItems(downloadStatuses),
@ -195,7 +196,7 @@ class ZimManageViewModel @Inject constructor(
)
private fun updateLibraryItems(
booksFromDao: Flowable<List<Book>>,
booksFromDao: Flowable<List<BookOnDisk>>,
downloads: Flowable<MutableList<DownloadModel>>,
library: Flowable<LibraryNetworkEntity>
) = Flowable.combineLatest(
@ -288,14 +289,14 @@ class ZimManageViewModel @Inject constructor(
) = allLanguages.firstOrNull { it.languageCode == locale.isO3Language }?.active == true
private fun combineLibrarySources(
booksOnFileSystem: List<Book>,
booksOnFileSystem: List<BookOnDisk>,
activeDownloads: List<DownloadModel>,
allLanguages: List<Language>,
libraryNetworkEntity: LibraryNetworkEntity,
filter: String,
fileSystemState: FileSystemState
): List<LibraryListItem> {
val downloadedBooksIds = booksOnFileSystem.map { it.id }
val downloadedBooksIds = booksOnFileSystem.map { it.book.id }
val downloadingBookIds = activeDownloads.map { it.book.id }
val activeLanguageCodes = allLanguages.filter(Language::active)
.map { it.languageCode }
@ -355,7 +356,7 @@ class ZimManageViewModel @Inject constructor(
private fun toBookItems(books: List<Book>) =
books.map { BookItem(it) }.toTypedArray()
private fun checkFileSystemForBooksOnRequest(booksFromDao: Flowable<List<Book>>) =
private fun checkFileSystemForBooksOnRequest(booksFromDao: Flowable<List<BookOnDisk>>) =
requestFileSystemCheck
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
@ -363,7 +364,7 @@ class ZimManageViewModel @Inject constructor(
.doOnNext { deviceListIsRefreshing.postValue(true) }
.switchMap(
{
updateBookDaoFromFilesystem(booksFromDao)
booksFromStorageNotIn(booksFromDao)
},
1
)
@ -376,24 +377,23 @@ class ZimManageViewModel @Inject constructor(
private fun books() = bookDao.books()
.subscribeOn(Schedulers.io())
.map { it.sortedBy { book -> book.title } }
.map { it.sortedBy { book -> book.book.title } }
private fun updateBookDaoFromFilesystem(booksFromDao: Flowable<List<Book>>) =
private fun booksFromStorageNotIn(booksFromDao: Flowable<List<BookOnDisk>>) =
storageObserver.booksOnFileSystem
.withLatestFrom(
booksFromDao,
booksFromDao.map { it.map { bookOnDisk -> bookOnDisk.book.id } },
BiFunction(this::removeBooksAlreadyInDao)
)
private fun removeBooksAlreadyInDao(
booksFromFileSystem: Collection<Book>,
booksFromDao: List<Book>
): List<Book> {
val idsInDao = booksFromDao.map { it.id }
return booksFromFileSystem.filterNot { idsInDao.contains(it.id) }
}
booksFromFileSystem: Collection<BookOnDisk>,
idsInDao: List<String>
) = booksFromFileSystem.filterNot { idsInDao.contains(it.book.id) }
private fun updateBookItems(booksFromDao: Flowable<List<Book>>) =
private fun updateBookItems(
booksFromDao: Flowable<List<BookOnDisk>>
) =
booksFromDao
.subscribe(
bookItems::postValue,
@ -407,7 +407,7 @@ class ZimManageViewModel @Inject constructor(
.map { it.filter { status -> status.state == Successful } }
.subscribe(
{
bookDao.saveBooks(it.map { downloadStatus -> downloadStatus.toBook() })
bookDao.saveBooks(it.map { downloadStatus -> downloadStatus.toBookOnDisk() })
downloadDao.delete(
*it.map { status -> status.downloadId }.toTypedArray()
)

View File

@ -3,37 +3,37 @@ package org.kiwix.kiwixmobile.zim_manager.fileselect_view
import android.support.v7.widget.RecyclerView
import android.view.ViewGroup
import org.kiwix.kiwixmobile.R.layout
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk
import org.kiwix.kiwixmobile.extensions.inflate
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.utils.BookUtils
class BooksAdapter(
class BooksOnDiskAdapter(
private val bookUtils: BookUtils,
private val onItemClick: (Book) -> Unit,
private val onItemLongClick: (Book) -> Unit
) : RecyclerView.Adapter<BooksViewHolder>() {
private val onItemClick: (BookOnDisk) -> Unit,
private val onItemLongClick: (BookOnDisk) -> Unit
) : RecyclerView.Adapter<BooksOnDiskViewHolder>() {
init {
setHasStableIds(true)
}
var itemList: List<Book> = mutableListOf()
var itemList: List<BookOnDisk> = mutableListOf()
set(value) {
field = value
notifyDataSetChanged()
}
override fun getItemId(position: Int) = itemList[position].databaseId
override fun getItemId(position: Int) = itemList[position].databaseId!!
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = BooksViewHolder(parent.inflate(layout.library_item, false), bookUtils)
) = BooksOnDiskViewHolder(parent.inflate(layout.library_item, false), bookUtils)
override fun getItemCount() = itemList.size
override fun onBindViewHolder(
holder: BooksViewHolder,
holder: BooksOnDiskViewHolder,
position: Int
) {
holder.bind(itemList[position], onItemClick, onItemLongClick)

View File

@ -14,23 +14,24 @@ import kotlinx.android.synthetic.main.library_item.size
import kotlinx.android.synthetic.main.library_item.title
import org.kiwix.kiwixmobile.KiwixApplication
import org.kiwix.kiwixmobile.downloader.model.Base64String
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk
import org.kiwix.kiwixmobile.extensions.setBitmap
import org.kiwix.kiwixmobile.extensions.setTextAndVisibility
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.utils.BookUtils
import org.kiwix.kiwixmobile.utils.NetworkUtils
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.KiloByte
class BooksViewHolder(
class BooksOnDiskViewHolder(
override val containerView: View,
private val bookUtils: BookUtils
) : ViewHolder(containerView),
LayoutContainer {
fun bind(
book: Book,
clickAction: (Book) -> Unit,
longClickAction: (Book) -> Unit
bookOnDisk: BookOnDisk,
clickAction: (BookOnDisk) -> Unit,
longClickAction: (BookOnDisk) -> Unit
) {
val book = bookOnDisk.book
title.setTextAndVisibility(book.title)
description.setTextAndVisibility(book.description)
creator.setTextAndVisibility(book.creator)
@ -39,15 +40,15 @@ class BooksViewHolder(
size.setTextAndVisibility(KiloByte(book.size).humanReadable)
language.text = bookUtils.getLanguage(book.getLanguage())
fileName.text = NetworkUtils.parseURL(
KiwixApplication.getInstance(), book.file.path
KiwixApplication.getInstance(), book.url
)
favicon.setBitmap(Base64String(book.favicon))
containerView.setOnClickListener {
clickAction.invoke(book)
clickAction.invoke(bookOnDisk)
}
containerView.setOnLongClickListener {
longClickAction.invoke(book)
longClickAction.invoke(bookOnDisk)
return@setOnLongClickListener true
}
}

View File

@ -3,7 +3,9 @@ package org.kiwix.kiwixmobile.zim_manager.fileselect_view
import android.content.Context
import android.util.Log
import io.reactivex.processors.PublishProcessor
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.database.DownloadDao
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk
import org.kiwix.kiwixmobile.downloader.model.DownloadModel
import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.utils.files.FileSearch
import org.kiwix.kiwixmobile.utils.files.FileSearch.ResultListener
@ -11,20 +13,21 @@ import javax.inject.Inject
class StorageObserver @Inject constructor(
private val context: Context,
private val sharedPreferenceUtil: SharedPreferenceUtil
private val sharedPreferenceUtil: SharedPreferenceUtil,
private val downloadDao: DownloadDao
) {
private val _booksOnFileSystem = PublishProcessor.create<Collection<Book>>()
private val _booksOnFileSystem = PublishProcessor.create<Collection<BookOnDisk>>()
val booksOnFileSystem = _booksOnFileSystem.distinctUntilChanged()
.doOnSubscribe { scanFiles() }
.doOnSubscribe { scanFiles(downloadDao.downloads) }
private fun scanFiles() {
FileSearch(context, object : ResultListener {
val foundBooks = mutableSetOf<Book>()
private fun scanFiles(downloads: MutableList<DownloadModel>) {
FileSearch(context, downloads, object : ResultListener {
val foundBooks = mutableSetOf<BookOnDisk>()
override fun onBookFound(book: Book) {
override fun onBookFound(book: BookOnDisk) {
foundBooks.add(book)
Log.i("Scanner", "File Search: Found Book " + book.title)
Log.i("Scanner", "File Search: Found Book " + book.book.title)
}
override fun onScanCompleted() {

View File

@ -40,8 +40,8 @@ import org.kiwix.kiwixmobile.ZimContentProvider
import org.kiwix.kiwixmobile.base.BaseFragment
import org.kiwix.kiwixmobile.database.BookDao
import org.kiwix.kiwixmobile.di.components.ActivityComponent
import org.kiwix.kiwixmobile.downloader.model.BookOnDisk
import org.kiwix.kiwixmobile.extensions.toast
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.utils.BookUtils
import org.kiwix.kiwixmobile.utils.Constants.REQUEST_STORAGE_PERMISSION
import org.kiwix.kiwixmobile.utils.DialogShower
@ -66,8 +66,8 @@ class ZimFileSelectFragment : BaseFragment() {
.get(ZimManageViewModel::class.java)
}
private val booksAdapter: BooksAdapter by lazy {
BooksAdapter(
private val booksOnDiskAdapter: BooksOnDiskAdapter by lazy {
BooksOnDiskAdapter(
bookUtils, this::open, this::tryToDelete
)
}
@ -92,12 +92,12 @@ class ZimFileSelectFragment : BaseFragment() {
super.onViewCreated(view, savedInstanceState)
zim_swiperefresh.setOnRefreshListener(this::requestFileSystemCheck)
zimfilelist.run {
adapter = booksAdapter
adapter = booksOnDiskAdapter
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
setHasFixedSize(true)
}
zimManageViewModel.bookItems.observe(this, Observer {
booksAdapter.itemList = it!!
booksOnDiskAdapter.itemList = it!!
checkEmpty(it)
})
zimManageViewModel.deviceListIsRefreshing.observe(this, Observer {
@ -110,7 +110,7 @@ class ZimFileSelectFragment : BaseFragment() {
checkPermissions()
}
private fun checkEmpty(books: List<Book>) {
private fun checkEmpty(books: List<BookOnDisk>) {
file_management_no_files.visibility =
if (books.isEmpty()) View.VISIBLE
else View.GONE
@ -136,7 +136,7 @@ class ZimFileSelectFragment : BaseFragment() {
zimManageViewModel.requestFileSystemCheck.onNext(Unit)
}
private fun open(it: Book) {
private fun open(it: BookOnDisk) {
ZimContentProvider.canIterate = false
if (!it.file.canRead()) {
context.toast(string.error_filenotfound)
@ -145,7 +145,7 @@ class ZimFileSelectFragment : BaseFragment() {
}
}
private fun tryToDelete(it: Book) {
private fun tryToDelete(it: BookOnDisk) {
dialogShower.show(DeleteZim, {
if (deleteSpecificZimFile(it)) {
context.toast(string.delete_specific_zim_toast)
@ -155,13 +155,13 @@ class ZimFileSelectFragment : BaseFragment() {
})
}
private fun deleteSpecificZimFile(book: Book): Boolean {
private fun deleteSpecificZimFile(book: BookOnDisk): Boolean {
val file = book.file
FileUtils.deleteZimFile(file)
if (file.exists()) {
return false
}
bookDao.deleteBook(book.id)
bookDao.deleteBook(book.databaseId)
return true
}
}

View File

@ -42,7 +42,7 @@ sealed class LibraryViewHolder<T : LibraryListItem>(override val containerView:
size.setTextAndVisibility(KiloByte(item.book.size).humanReadable)
language.text = bookUtils.getLanguage(item.book.getLanguage())
fileName.text = NetworkUtils.parseURL(
KiwixApplication.getInstance(), item.book.file?.path ?: ""
KiwixApplication.getInstance(), item.book.url
)
favicon.setBitmap(Base64String(item.book.favicon))