1 package com.moiseum.wolnelektury.view.book;
3 import android.os.Bundle;
4 import android.util.Log;
6 import com.folioreader.util.AppUtil;
7 import com.moiseum.wolnelektury.base.WLApplication;
8 import com.moiseum.wolnelektury.base.mvp.FragmentPresenter;
9 import com.moiseum.wolnelektury.connection.downloads.FileCacheUtils;
10 import com.moiseum.wolnelektury.connection.downloads.FileDownloadIntentService;
11 import com.moiseum.wolnelektury.connection.models.BookDetailsModel;
12 import com.moiseum.wolnelektury.connection.models.BookModel;
13 import com.moiseum.wolnelektury.connection.models.FavouriteStateModel;
14 import com.moiseum.wolnelektury.connection.models.ReadingStateModel;
15 import com.moiseum.wolnelektury.connection.services.BooksService;
16 import com.moiseum.wolnelektury.events.BookFavouriteEvent;
17 import com.moiseum.wolnelektury.storage.BookStorage;
18 import com.moiseum.wolnelektury.utils.SharedPreferencesUtils;
19 import com.moiseum.wolnelektury.view.book.components.ProgressDownloadButton;
21 import org.greenrobot.eventbus.EventBus;
22 import org.greenrobot.eventbus.Subscribe;
23 import org.greenrobot.eventbus.ThreadMode;
25 import java.util.ArrayList;
26 import java.util.List;
28 import io.reactivex.Completable;
29 import io.reactivex.Single;
30 import io.reactivex.android.schedulers.AndroidSchedulers;
31 import io.reactivex.schedulers.Schedulers;
34 * Created by Piotr Ostrowski on 17.11.2017.
37 class BookPresenter extends FragmentPresenter<BookView> {
39 private static final String TAG = BookPresenter.class.getSimpleName();
41 private BookDetailsModel book;
42 private BookModel storedBook;
43 private String bookSlug;
44 private BookType bookType;
46 private SharedPreferencesUtils preferences = WLApplication.getInstance().getPreferences();
47 private BooksService booksService = WLApplication.getInstance().getRestClient().obtainBookService();
48 private BookStorage storage = WLApplication.getInstance().getBookStorage();
50 BookPresenter(String slug, BookType type, BookView view) {
57 public void onViewCreated(Bundle savedInstanceState) {
58 super.onViewCreated(savedInstanceState);
60 getView().showPremiumLock(!preferences.isUserPremium() && bookType.shouldShowPremiumLock());
61 EventBus.getDefault().register(this);
65 public void onResume() {
67 this.storedBook = storage.find(bookSlug);
68 if (storedBook != null && storedBook.isEbookDownloaded()) {
69 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_READING, false);
70 getView().updateReadingProgress(storedBook.getCurrentChapter(), storedBook.getTotalChapters(), false);
72 if (storedBook != null && storedBook.isAudioDownloaded()) {
73 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_READING, true);
74 getView().updateReadingProgress(storedBook.getCurrentAudioChapter(), storedBook.getTotalAudioChapters(), true);
79 public void onDestroy() {
81 EventBus.getDefault().unregister(this);
84 @Subscribe(threadMode = ThreadMode.MAIN)
85 public void onMessageEvent(FileCacheUtils.DownloadProgressEvent event) {
86 if (event.getFileUrl().equals(book.getEpub())) {
87 int percentage = (int) ((double) event.getDownloaded() / (double) event.getTotal() * 100.0);
88 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_DOWNLOADING, false);
89 getView().showCurrentStateProgress(percentage, false);
90 } else if (book.getAudiobookFilesUrls().contains(event.getFileUrl())) {
91 ArrayList<String> filesUrls = book.getAudiobookFilesUrls();
92 int fileIndex = filesUrls.indexOf(event.getFileUrl());
93 double part = (double) event.getDownloaded() / (double) event.getTotal() / (double) filesUrls.size();
94 double completed = (double) fileIndex / (double) filesUrls.size();
95 int percentage = (int) ((part + completed) * 100.0);
96 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_DOWNLOADING, true);
97 getView().showCurrentStateProgress(percentage, true);
101 @Subscribe(threadMode = ThreadMode.MAIN)
102 public void onMessageEvent(FileDownloadIntentService.DownloadFileEvent event) {
103 if (event.getFileUrl().equals(book.getEpub())) {
104 if (event.isSuccess()) {
105 storeDownloadedBook(false);
106 getView().showCurrentStateProgress(0, false);
107 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_READING, false);
110 getView().showCurrentStateProgress(0, false);
111 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_INITIAL, false);
112 getView().showDownloadFileError();
114 } else if (book.getAudiobookFilesUrls().contains(event.getFileUrl())) {
115 if (event.isSuccess()) {
116 ArrayList<String> filesUrls = book.getAudiobookFilesUrls();
117 int fileIndex = filesUrls.indexOf(event.getFileUrl());
118 if (fileIndex == filesUrls.size() - 1) {
119 storeDownloadedBook(true);
120 getView().showCurrentStateProgress(0, true);
121 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_READING, true);
124 int percentage = (int) ((fileIndex + 1.0) / ((double) filesUrls.size()) * 100.0);
125 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_DOWNLOADING, true);
126 getView().showCurrentStateProgress(percentage, true);
129 getView().showCurrentStateProgress(0, true);
130 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_INITIAL, true);
131 getView().showDownloadFileError();
137 void launchEbookForState(ProgressDownloadButton.ProgressDownloadButtonState state) {
138 if (state.isDownloaded()) {
141 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_DOWNLOADING, false);
142 FileDownloadIntentService.downloadFile(getView().getContext(), book.getEpub());
146 void launchAudiobookForState(ProgressDownloadButton.ProgressDownloadButtonState state) {
147 if (state.isDownloaded()) {
150 getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_DOWNLOADING, true);
151 FileDownloadIntentService.downloadFiles(getView().getContext(), book.getAudiobookFilesUrls());
155 void reloadBookDetails() {
160 addDisposable(FileCacheUtils.deleteEbookFile(book.getEpub())
161 .andThen(Completable.fromAction(this::updateStoredBookAfterDeletion))
162 .subscribeOn(Schedulers.io())
163 .observeOn(AndroidSchedulers.mainThread())
165 () -> getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_INITIAL, false),
171 void deleteAudiobook() {
172 addDisposable(FileCacheUtils.deleteAudiobookFiles(book.getAudiobookFilesUrls())
173 .andThen(Completable.fromAction(this::updateStoredAudiobookAfterDeletion))
174 .subscribeOn(Schedulers.io())
175 .observeOn(AndroidSchedulers.mainThread())
177 () -> getView().changeDownloadButtonState(ProgressDownloadButton.ProgressDownloadButtonState.STATE_INITIAL, true),
183 void onShareEbookClicked() {
184 getView().startShareActivity(book.getUrl());
187 void onFavouriteEbookClicked() {
188 if (!book.getFavouriteState()) {
189 getView().startLikeClicked();
190 updateFavouriteState(true);
192 getView().stopLikeClicked();
193 updateFavouriteState(false);
197 void onBackFromReader(String bookName, int currentChapter, int count) {
198 storedBook.setEbookName(bookName);
199 storedBook.setCurrentChapter(currentChapter);
200 storedBook.setTotalChapters(count);
201 storage.update(storedBook);
202 getView().updateReadingProgress(currentChapter, count, false);
204 if (currentChapter == count && book.getState() == ReadingStateModel.ReadingState.STATE_READING) {
205 updateReadingState(ReadingStateModel.ReadingState.STATE_COMPLETED);
209 // ------------------------------------------------------------------------------------------------------------------------------------------
211 // ------------------------------------------------------------------------------------------------------------------------------------------
213 private void updateStoredBookAfterDeletion() {
214 if (!storedBook.isAudioDownloaded()) {
215 storage.remove(storedBook.getSlug(), true);
220 AppUtil.removeBookState(WLApplication.getInstance().getApplicationContext(), storedBook.getEbookName());
221 storedBook.setEbookName(null);
222 storedBook.setEbookFileUrl(null);
223 storedBook.setCurrentChapter(0);
224 storedBook.setTotalChapters(0);
225 storage.update(storedBook);
228 private void updateStoredAudiobookAfterDeletion() {
229 if (!storedBook.isEbookDownloaded()) {
230 storage.remove(storedBook.getSlug(), true);
235 storedBook.setAudioFileUrls(null);
236 storedBook.setCurrentAudioChapter(0);
237 storedBook.setTotalAudioChapters(0);
238 storage.update(storedBook);
241 private Single<BookDetailsModel> getBookDetails() {
242 Single<ReadingStateModel> readingStateSingle = preferences.isUserLoggedIn() ? booksService.getReadingState(bookSlug) : Single.just(new ReadingStateModel());
243 Single<FavouriteStateModel> favouriteStateModelSingle = preferences.isUserLoggedIn() ? booksService.getFavouriteState(bookSlug) : Single.just(new FavouriteStateModel());
244 Single<BookDetailsModel> bookDetailsSingle = Single.zip(
246 favouriteStateModelSingle,
247 booksService.getBookDetails(bookSlug),
248 (readingStateModel, favouriteStateModel, bookDetailsModel) -> {
249 bookDetailsModel.setState(readingStateModel.getState());
250 bookDetailsModel.setFavouriteState(favouriteStateModel.getState());
251 return bookDetailsModel;
253 return bookDetailsSingle.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
256 private void loadBookDetails() {
257 addDisposable(getBookDetails().subscribe(bookDetailsModel -> {
258 book = bookDetailsModel;
259 getView().initializeBookView(bookDetailsModel);
260 }, error -> getView().showInitializationError()));
263 private void updateReadingState(ReadingStateModel.ReadingState state) {
264 if (preferences.isUserLoggedIn()) {
265 addDisposable(booksService.setReadingState(bookSlug, state.getStateName())
266 .subscribeOn(Schedulers.io())
267 .observeOn(AndroidSchedulers.mainThread())
268 .subscribe(updatedState -> book.setState(updatedState.getState()), error -> Log.e(TAG, "Failed to update reading state.", error)));
272 private void updateFavouriteState(boolean state) {
273 addDisposable(booksService.setFavouriteState(bookSlug, book.getFavouriteString(state))
274 .subscribeOn(Schedulers.io())
275 .observeOn(AndroidSchedulers.mainThread())
276 .subscribe(updatedState -> {
277 book.setFavouriteState(state);
278 EventBus.getDefault().post(new BookFavouriteEvent(state));
279 }, error -> Log.e(TAG, "Failed to update favourite state.", error)));
282 private void launchFolioReader() {
283 if (book.getState() == ReadingStateModel.ReadingState.STATE_NOT_STARTED) {
284 updateReadingState(ReadingStateModel.ReadingState.STATE_READING);
286 String downloadedBookUrl = FileCacheUtils.getCachedFileForUrl(book.getEpub());
287 if (downloadedBookUrl != null) {
288 getView().openBook(downloadedBookUrl);
292 private void launchAudioPlayer() {
293 if (book.getState() == ReadingStateModel.ReadingState.STATE_NOT_STARTED) {
294 updateReadingState(ReadingStateModel.ReadingState.STATE_READING);
296 getView().launchPlayer(book);
299 private void storeDownloadedBook(boolean forAudiobook) {
300 BookModel stored = storedBook == null ? book.getStorageModel(bookSlug) : storedBook;
302 List<String> mediaUrls = book.getAudiobookFilesUrls();
303 stored.setAudioFileUrls(mediaUrls);
304 stored.setTotalAudioChapters(mediaUrls.size());
306 stored.setEbookFileUrl(book.getEpub());
308 if (storedBook == null) {
310 storage.add(storedBook);
312 storage.update(stored);
316 public void showFavouriteButton(BookDetailsModel book) {
317 if(preferences.isUserLoggedIn()) {
318 getView().showFavouriteButton(book);