package com.quran.labs.androidquran.presenter.bookmark; import android.support.v4.util.Pair; import com.quran.labs.androidquran.dao.Bookmark; import com.quran.labs.androidquran.dao.Tag; import com.quran.labs.androidquran.model.bookmark.BookmarkModel; import com.quran.labs.androidquran.presenter.Presenter; import com.quran.labs.androidquran.ui.fragment.TagBookmarkDialog; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; @Singleton public class TagBookmarkPresenter implements Presenter<TagBookmarkDialog> { private final BookmarkModel bookmarkModel; private final HashSet<Long> checkedTags = new HashSet<>(); private TagBookmarkDialog dialog; private List<Tag> tags; private long[] bookmarkIds; private boolean madeChanges; private boolean saveImmediate; private boolean shouldRefreshTags; private Bookmark potentialAyahBookmark; @Inject TagBookmarkPresenter(BookmarkModel bookmarkModel) { this.bookmarkModel = bookmarkModel; this.bookmarkModel.tagsObservable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(tag -> { shouldRefreshTags = true; if (tags != null && dialog != null) { // change this if we support updating tags from outside of QuranActivity tags.add(tags.size() - 1, tag); checkedTags.add(tag.id); dialog.setData(tags, checkedTags); setMadeChanges(); } }); } public void setBookmarksMode(long[] bookmarkIds) { setMode(bookmarkIds, null); } public void setAyahBookmarkMode(int sura, int ayah, int page) { setMode(null, new Bookmark(-1, sura, ayah, page)); } private void setMode(long[] bookmarkIds, Bookmark potentialAyahBookmark) { this.bookmarkIds = bookmarkIds; this.potentialAyahBookmark = potentialAyahBookmark; saveImmediate = this.potentialAyahBookmark != null; checkedTags.clear(); refresh(); } void refresh() { Single.zip(getTagsObservable(), getBookmarkTagIdsObservable(), Pair::new) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::onRefreshedData); } void onRefreshedData(Pair<List<Tag>, List<Long>> data) { List<Tag> tags1 = data.first; int numberOfTags = tags1.size(); if (numberOfTags == 0 || tags1.get(numberOfTags - 1).id != -1) { tags1.add(new Tag(-1, "")); } List<Long> bookmarkTags = data.second; checkedTags.clear(); for (int i = 0, tagsSize = tags1.size(); i < tagsSize; i++) { Tag tag = tags1.get(i); if (bookmarkTags.contains(tag.id)) { checkedTags.add(tag.id); } } madeChanges = false; TagBookmarkPresenter.this.tags = tags1; shouldRefreshTags = false; if (dialog != null) { dialog.setData(TagBookmarkPresenter.this.tags, checkedTags); } } private Single<List<Tag>> getTagsObservable() { if (tags == null || shouldRefreshTags) { return bookmarkModel.getTagsObservable(); } else { return Single.just(tags); } } public void saveChanges() { if (madeChanges) { getBookmarkIdsObservable() .flatMap(bookmarkIds -> bookmarkModel.updateBookmarkTags(bookmarkIds, checkedTags, bookmarkIds.length == 1)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(aBoolean -> { onSaveChangesDone(); }); } else { onSaveChangesDone(); } } void onSaveChangesDone() { madeChanges = false; } /** * Get an Observable with the list of bookmark ids that will be tagged. * * @return the list of bookmark ids to tag */ private Observable<long[]> getBookmarkIdsObservable() { Observable<long[]> observable; if (bookmarkIds != null) { // if we already have a list, we just use that observable = Observable.just(bookmarkIds); } else { // if we don't have a bookmark id, we'll add the bookmark and use its id observable = bookmarkModel.safeAddBookmark(potentialAyahBookmark.sura, potentialAyahBookmark.ayah, potentialAyahBookmark.page) .map(bookmarkId -> new long[]{ bookmarkId }); } return observable; } public boolean toggleTag(long id) { boolean result = false; if (id > 0) { if (checkedTags.contains(id)) { checkedTags.remove(id); } else { checkedTags.add(id); result = true; } setMadeChanges(); } else if (dialog != null) { dialog.showAddTagDialog(); } return result; } void setMadeChanges() { madeChanges = true; if (saveImmediate) { saveChanges(); } } private Single<List<Long>> getBookmarkTagIdsObservable() { Single<Long> bookmarkId; if (potentialAyahBookmark != null) { bookmarkId = bookmarkModel.getBookmarkId(potentialAyahBookmark.sura, potentialAyahBookmark.ayah, potentialAyahBookmark.page); } else { bookmarkId = Single.just( bookmarkIds != null && bookmarkIds.length == 1 ? bookmarkIds[0] : 0); } return bookmarkModel.getBookmarkTagIds(bookmarkId) .defaultIfEmpty(new ArrayList<>()) .toSingle(); } @Override public void bind(TagBookmarkDialog dialog) { this.dialog = dialog; if (tags != null) { // replay the last set of tags and checked tags that we had. this.dialog.setData(tags, checkedTags); } } @Override public void unbind(TagBookmarkDialog dialog) { if (dialog == this.dialog) { this.dialog = null; } } }