package gr.thmmy.mthmmy.viewmodel; import android.arch.lifecycle.MutableLiveData; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; import java.util.ArrayList; import gr.thmmy.mthmmy.activities.settings.SettingsActivity; import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTaskCompleted, PrepareForReply.OnPrepareForReplyFinished, PrepareForEditTask.OnPrepareEditFinished { /** * topic state */ private boolean editingPost = false; private boolean writingReply = false; /** * A list of {@link Post#getPostIndex()} for building quotes for replying */ private ArrayList toQuoteList = new ArrayList<>(); /** * caches the expand/collapse state of the user extra info in the current page for the recyclerview */ private ArrayList isUserExtraInfoVisibile = new ArrayList<>(); /** * holds the adapter position of the post being edited */ private int postBeingEditedPosition; private TopicTask currentTopicTask; private PrepareForEditTask currentPrepareForEditTask; private PrepareForReply currentPrepareForReplyTask; //callbacks for topic activity private TopicTask.TopicTaskObserver topicTaskObserver; private DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks; private ReplyTask.ReplyTaskCallbacks replyFinishListener; private PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks; private EditTask.EditTaskCallbacks editTaskCallbacks; private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; /** * Holds the value (index) of the page to be requested when a user interaction with bottom * navigation bar occurs, aka the value that the page indicator shows */ private MutableLiveData pageIndicatorIndex = new MutableLiveData<>(); private MutableLiveData replyPageUrl = new MutableLiveData<>(); private MutableLiveData pageTopicId = new MutableLiveData<>(); private MutableLiveData topicTitle = new MutableLiveData<>(); private MutableLiveData> postsList = new MutableLiveData<>(); private MutableLiveData focusedPostIndex = new MutableLiveData<>(); private MutableLiveData topicTaskResultCode = new MutableLiveData<>(); private MutableLiveData topicTreeAndMods = new MutableLiveData<>(); private MutableLiveData topicViewers = new MutableLiveData<>(); private String topicUrl; private int currentPageIndex; private int pageCount; private MutableLiveData prepareForReplyResult = new MutableLiveData<>(); private MutableLiveData prepareForEditResult = new MutableLiveData<>(); public void loadUrl(String pageUrl) { stopLoading(); topicUrl = pageUrl; currentTopicTask = new TopicTask(topicTaskObserver, this); currentTopicTask.execute(pageUrl); } public void reloadPage() { if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); loadUrl(topicUrl); } public void performPageChange() { if (pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int pageRequested = pageIndicatorIndex.getValue() - 1; if (pageRequested != currentPageIndex - 1) { loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(pageRequested * 15)); pageIndicatorIndex.setValue(pageRequested + 1); } else { stopLoading(); } } public void prepareForReply() { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); stopLoading(); setPageIndicatorIndex(pageCount, true); currentPrepareForReplyTask = new PrepareForReply(prepareForReplyCallbacks, this, replyPageUrl.getValue()); currentPrepareForReplyTask.execute(toQuoteList.toArray(new Integer[0])); } public void postReply(Context context, String subject, String reply) { if (prepareForReplyResult.getValue() == null) { throw new NullPointerException("Reply preparation was not found!"); } PrepareForReplyResult replyForm = prepareForReplyResult.getValue(); boolean includeAppSignature = true; SessionManager sessionManager = BaseActivity.getSessionManager(); if (sessionManager.isLoggedIn()) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); includeAppSignature = prefs.getBoolean(SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY, true); } toQuoteList.clear(); new ReplyTask(replyFinishListener, includeAppSignature).execute(subject, reply, replyForm.getNumReplies(), replyForm.getSeqnum(), replyForm.getSc(), replyForm.getTopic()); } public void deletePost(String postDeleteUrl) { new DeleteTask(deleteTaskCallbacks).execute(postDeleteUrl); } public void prepareForEdit(int position, String postEditURL) { if (replyPageUrl.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); stopLoading(); currentPrepareForEditTask = new PrepareForEditTask(prepareForEditCallbacks, this, position, replyPageUrl.getValue()); currentPrepareForEditTask.execute(postEditURL); } public void editPost(int position, String subject, String message) { if (prepareForEditResult.getValue() == null) throw new NullPointerException("Edit preparation was not found!"); PrepareForEditResult editResult = prepareForEditResult.getValue(); new EditTask(editTaskCallbacks, position).execute(editResult.getCommitEditUrl(), message, editResult.getNumReplies(), editResult.getSeqnum(), editResult.getSc(), subject, editResult.getTopic()); } /** * cancel tasks that change the ui * topic, prepare for edit, prepare for reply tasks need to cancel all other ui changing tasks * before starting */ public void stopLoading() { if (currentTopicTask != null && currentTopicTask.getStatus() == AsyncTask.Status.RUNNING) { currentTopicTask.cancel(true); pageIndicatorIndex.setValue(currentPageIndex); topicTaskObserver.onTopicTaskCancelled(); } if (currentPrepareForEditTask != null && currentPrepareForEditTask.getStatus() == AsyncTask.Status.RUNNING) { currentPrepareForEditTask.cancel(true); prepareForEditCallbacks.onPrepareEditCancelled(); } if (currentPrepareForReplyTask != null && currentPrepareForReplyTask.getStatus() == AsyncTask.Status.RUNNING) { currentPrepareForReplyTask.cancel(true); prepareForReplyCallbacks.onPrepareForReplyCancelled(); } // no need to cancel reply, edit and delete task, user should not have to wait for the ui // after he is done posting, editing or deleting } // callbacks for viewmodel @Override public void onTopicTaskCompleted(TopicTaskResult result) { if (result.getResultCode() == TopicTask.ResultCode.SUCCESS) { currentPageIndex = result.getCurrentPageIndex(); pageCount = result.getPageCount(); topicTreeAndMods.setValue(result.getTopicTreeAndMods()); topicViewers.setValue(result.getTopicViewers()); pageTopicId.setValue(result.getLoadedPageTopicId()); replyPageUrl.setValue(result.getReplyPageUrl()); topicTitle.setValue(result.getTopicTitle()); pageIndicatorIndex.setValue(result.getCurrentPageIndex()); postsList.setValue(result.getNewPostsList()); focusedPostIndex.setValue(result.getFocusedPostIndex()); isUserExtraInfoVisibile.clear(); for (int i = 0; i < result.getNewPostsList().size(); i++) { isUserExtraInfoVisibile.add(false); } } topicTaskResultCode.setValue(result.getResultCode()); } @Override public void onPrepareForReplyFinished(PrepareForReplyResult result) { prepareForReplyResult.setValue(result); } @Override public void onPrepareEditFinished(PrepareForEditResult result, int position) { postBeingEditedPosition = position; prepareForEditResult.setValue(result); } public void incrementPageRequestValue(int step, boolean changePage) { if (pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int oldIndicatorIndex = pageIndicatorIndex.getValue(); if (oldIndicatorIndex <= pageCount - step) { pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() + step); } else pageIndicatorIndex.setValue(pageCount); if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); } public void decrementPageRequestValue(int step, boolean changePage) { if (pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int oldIndicatorIndex = pageIndicatorIndex.getValue(); if (oldIndicatorIndex > step) { pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() - step); } else pageIndicatorIndex.setValue(1); if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) performPageChange(); } public void setPageIndicatorIndex(int pageIndicatorIndex, boolean changePage) { if (this.pageIndicatorIndex.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); int oldIndicatorIndex = this.pageIndicatorIndex.getValue(); this.pageIndicatorIndex.setValue(pageIndicatorIndex); if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) performPageChange(); } // <-------------Just getters, setters and helper methods below here----------------> public MutableLiveData getTopicViewers() { return topicViewers; } public MutableLiveData getTopicTreeAndMods() { return topicTreeAndMods; } public MutableLiveData getTopicTaskResultCode() { return topicTaskResultCode; } public MutableLiveData getFocusedPostIndex() { return focusedPostIndex; } public MutableLiveData> getPostsList() { return postsList; } public MutableLiveData getReplyPageUrl() { return replyPageUrl; } public MutableLiveData getPageTopicId() { return pageTopicId; } public MutableLiveData getTopicTitle() { return topicTitle; } public String getTopicUrl() { return topicUrl; } public MutableLiveData getPageIndicatorIndex() { return pageIndicatorIndex; } public boolean isUserExtraInfoVisible(int position) { return isUserExtraInfoVisibile.get(position); } public void hideUserInfo(int position) { isUserExtraInfoVisibile.set(position, false); } public void toggleUserInfo(int position) { isUserExtraInfoVisibile.set(position, !isUserExtraInfoVisibile.get(position)); } public ArrayList getToQuoteList() { return toQuoteList; } public void postIndexToggle(Integer postIndex) { if (toQuoteList.contains(postIndex)) toQuoteList.remove(postIndex); else toQuoteList.add(postIndex); } public void setTopicTaskObserver(TopicTask.TopicTaskObserver topicTaskObserver) { this.topicTaskObserver = topicTaskObserver; } public void setDeleteTaskCallbacks(DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks) { this.deleteTaskCallbacks = deleteTaskCallbacks; } public void setReplyFinishListener(ReplyTask.ReplyTaskCallbacks replyFinishListener) { this.replyFinishListener = replyFinishListener; } public void setPrepareForEditCallbacks(PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks) { this.prepareForEditCallbacks = prepareForEditCallbacks; } public void setEditTaskCallbacks(EditTask.EditTaskCallbacks editTaskCallbacks) { this.editTaskCallbacks = editTaskCallbacks; } public void setPrepareForReplyCallbacks(PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks) { this.prepareForReplyCallbacks = prepareForReplyCallbacks; } public MutableLiveData getPrepareForReplyResult() { return prepareForReplyResult; } public MutableLiveData getPrepareForEditResult() { return prepareForEditResult; } public void setEditingPost(boolean editingPost) { this.editingPost = editingPost; } public boolean isEditingPost() { return editingPost; } public int getPostBeingEditedPosition() { return postBeingEditedPosition; } public boolean canReply() { return replyPageUrl.getValue() != null; } public boolean isWritingReply() { return writingReply; } public void setWritingReply(boolean writingReply) { this.writingReply = writingReply; } public int getCurrentPageIndex() { if (currentPageIndex == 0) throw new NullPointerException("No page has been loaded yet!"); return currentPageIndex; } public int getPageCount() { if (pageCount == 0) throw new NullPointerException("No page has been loaded yet!"); return pageCount; } public String getPostBeingEditedText() { if (prepareForEditResult.getValue() == null) throw new NullPointerException("Edit preparation was not found!"); return prepareForEditResult.getValue().getPostText(); } public String getBuildedQuotes() { if (prepareForReplyResult.getValue() == null) throw new NullPointerException("Reply preparation was not found"); return prepareForReplyResult.getValue().getBuildedQuotes(); } public int postCount() { if (postsList.getValue() == null) throw new NullPointerException("No page has been loaded yet!"); return postsList.getValue().size(); } }