/*
Copyright (C) 2014 Prasanna Thirumalai
This file is part of StackX.
StackX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
StackX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with StackX. If not, see <http://www.gnu.org/licenses/>.
*/
package com.prasanna.android.stacknetwork;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.Toast;
import com.prasanna.android.http.HttpException;
import com.prasanna.android.stacknetwork.fragment.AnswerFragment;
import com.prasanna.android.stacknetwork.fragment.CommentFragment;
import com.prasanna.android.stacknetwork.fragment.CommentFragment.OnCommentChangeListener;
import com.prasanna.android.stacknetwork.fragment.CommentFragment.OnShowCommentsListener;
import com.prasanna.android.stacknetwork.fragment.PostCommentFragment;
import com.prasanna.android.stacknetwork.fragment.QuestionFragment;
import com.prasanna.android.stacknetwork.model.Answer;
import com.prasanna.android.stacknetwork.model.Comment;
import com.prasanna.android.stacknetwork.model.Question;
import com.prasanna.android.stacknetwork.model.WritePermission;
import com.prasanna.android.stacknetwork.receiver.RestQueryResultReceiver;
import com.prasanna.android.stacknetwork.receiver.RestQueryResultReceiver.StackXRestQueryResultReceiver;
import com.prasanna.android.stacknetwork.service.QuestionDetailsIntentService;
import com.prasanna.android.stacknetwork.service.WriteIntentService;
import com.prasanna.android.stacknetwork.utils.AppUtils;
import com.prasanna.android.stacknetwork.utils.OperatingSite;
import com.prasanna.android.stacknetwork.utils.SharedPreferencesUtil;
import com.prasanna.android.stacknetwork.utils.StringConstants;
import com.viewpagerindicator.TitlePageIndicator;
public class QuestionActivity extends AbstractUserActionBarActivity implements OnPageChangeListener,
StackXRestQueryResultReceiver, PageSelectAdapter, OnShowCommentsListener {
private boolean serviceRunningForAnswers = false;
private boolean serviceRunningForFavorite = false;
private Question question;
private QuestionViewPageAdapter questionViewPageAdapter;
private ViewPager viewPager;
private TitlePageIndicator titlePageIndicator;
private RestQueryResultReceiver resultReceiver;
private QuestionFragment questionFragment;
private CommentFragment commentFragment;
private PostCommentFragment postCommentFragment;
private HashMap<String, String> commentsDraft = new HashMap<String, String>();
private Menu menu;
public class QuestionViewPageAdapter extends FragmentPagerAdapter {
public QuestionViewPageAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
if (question == null) return 1;
else return question.answers == null ? 1 : 1 + question.answers.size();
}
@Override
public CharSequence getPageTitle(int position) {
if (position == 0) return QuestionActivity.this.getString(R.string.question);
else {
if (question.answers.get(position - 1).accepted) return QuestionActivity.this.getString(R.string.accepted)
+ " " + QuestionActivity.this.getString(R.string.answer);
else return QuestionActivity.this.getString(R.string.answer) + " " + position;
}
}
@Override
public Fragment getItem(int position) {
if (position == 0) return QuestionActivity.this.questionFragment;
else {
Fragment fragment = getFragmentManager().findFragmentByTag(getViewPagerFragmentTag(position));
if (fragment == null)
return AnswerFragment.newFragment(question.answers.get(position - 1), QuestionActivity.this,
question.owner.id == OperatingSite.getSite().userId, question.hasAcceptedAnswer);
return fragment;
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_title_indicator);
resultReceiver = new RestQueryResultReceiver(new Handler());
resultReceiver.setReceiver(this);
if (questionFragment == null) questionFragment = QuestionFragment.newFragment();
setupViewPager();
if (savedInstanceState != null && savedInstanceState.getSerializable(StringConstants.QUESTION) != null) question =
(Question) savedInstanceState.getSerializable(StringConstants.QUESTION);
else prepareIntentAndStartService();
}
@Override
protected boolean shouldSearchViewBeEnabled() {
return false;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
boolean ret = super.onPrepareOptionsMenu(menu);
if (menu != null) {
this.menu = menu;
setupMenuIfAuthenticatedUser();
}
return ret;
}
private MenuItem setupFavoriteActionBarIcon() {
MenuItem favorite = menu.findItem(R.id.menu_favorite);
if (question != null && question.favorited) {
favorite.setIcon(R.drawable.favorited);
} else {
favorite.setIcon(R.drawable.favorite);
}
return favorite;
}
private void setupMenuIfAuthenticatedUser() {
if (AppUtils.inAuthenticatedRealm(this)) {
MenuItem favorite = setupFavoriteActionBarIcon();
favorite.setVisible(true);
menu.findItem(R.id.menu_refresh).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
setupAddComment(menu);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_favorite:
startServiceToFavoriteQuestion();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void startServiceToFavoriteQuestion() {
if (!serviceRunningForFavorite) {
Intent intent = new Intent(this, QuestionDetailsIntentService.class);
if (question.favorited) intent.putExtra(StringConstants.ACTION, QuestionDetailsIntentService.FAVORITE_UNDO);
else intent.putExtra(StringConstants.ACTION, QuestionDetailsIntentService.FAVORITE);
intent.putExtra(StringConstants.RESULT_RECEIVER, resultReceiver);
intent.putExtra(StringConstants.SITE, getIntent().getStringExtra(StringConstants.SITE));
intent.putExtra(StringConstants.ID, question.id);
startService(intent);
serviceRunningForFavorite = true;
}
}
private void setupAddComment(Menu menu) {
MenuItem newCommentMenuItem = menu.findItem(R.id.menu_new_comment);
newCommentMenuItem.setVisible(true);
newCommentMenuItem.getActionView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setupPostCommentFragment(null);
}
});
}
private void setupPostCommentFragment(String defaultText) {
if (viewPager.getCurrentItem() == 0) {
displayPostCommentFragment("Comment on question by " + question.owner.displayName, question.id, 0, question.id
+ "-comment", defaultText);
} else {
Answer answer = question.answers.get(viewPager.getCurrentItem() - 1);
displayPostCommentFragment("Comment on answer by " + answer.owner.getDisplayName(), answer.id,
viewPager.getCurrentItem(), answer.id + "-comment", defaultText);
}
}
private void displayPostCommentFragment(String title, long id, int viewPagerPosition, String fragmentTag,
String defaultText) {
postCommentFragment = new PostCommentFragment();
postCommentFragment.setPostId(id);
postCommentFragment.setViewPagerPosition(viewPagerPosition);
postCommentFragment.setTitle(title);
postCommentFragment.setResultReceiver(resultReceiver);
if (commentsDraft.get(fragmentTag) != null) postCommentFragment.setDraftText(commentsDraft.get(fragmentTag));
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, postCommentFragment, fragmentTag);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.addToBackStack(fragmentTag);
transaction.commit();
}
private void setupViewPager() {
questionViewPageAdapter = new QuestionViewPageAdapter(getFragmentManager());
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(questionViewPageAdapter);
titlePageIndicator = (TitlePageIndicator) findViewById(R.id.indicator);
titlePageIndicator.setViewPager(viewPager);
titlePageIndicator.setOnPageChangeListener(this);
}
private void prepareIntentAndStartService() {
Intent intent = new Intent(this, QuestionDetailsIntentService.class);
intent.putExtra(StringConstants.ACTION, QuestionDetailsIntentService.QA);
intent.putExtra(StringConstants.RESULT_RECEIVER, resultReceiver);
setProgressBarIndeterminateVisibility(true);
if (StringConstants.QUESTION_ID.equals(getIntent().getAction())) {
long questionId = getIntent().getLongExtra(StringConstants.QUESTION_ID, 0);
intent.setAction(StringConstants.QUESTION_ID);
intent.putExtra(StringConstants.QUESTION_ID, questionId);
intent.putExtra(StringConstants.SITE, getIntent().getStringExtra(StringConstants.SITE));
startService(intent);
} else {
Question metaDetails = (Question) getIntent().getSerializableExtra(StringConstants.QUESTION);
if (metaDetails != null) question = Question.copyMetaDeta(metaDetails);
if (question != null) {
questionFragment.setQuestion(question);
intent.setAction(StringConstants.QUESTION);
intent.putExtra(StringConstants.QUESTION_ID, question.id);
intent.putExtra(StringConstants.QUESTION, question);
intent.putExtra(StringConstants.SITE, getIntent().getStringExtra(StringConstants.SITE));
intent.putExtra(StringConstants.REFRESH, getIntent().getBooleanExtra(StringConstants.REFRESH, false));
startService(intent);
}
}
}
@Override
public void onBackPressed() {
if (commentFragment != null && commentFragment.isVisible()) commentFragment.onBackPressed();
super.onBackPressed();
dismissPostCommentFragmentIfVisible(false);
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (question != null) outState.putSerializable(StringConstants.QUESTION, question);
super.onSaveInstanceState(outState);
}
@Override
protected void refresh() {
Intent intent = getIntent();
finish();
intent.putExtra(StringConstants.REFRESH, true);
startActivity(intent);
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int position) {
int numAnswersDisplayed = questionViewPageAdapter.getCount() - 1;
if (commentFragment != null && commentFragment.isVisible()) {
getFragmentManager().popBackStackImmediate();
commentFragment = null;
}
dismissPostCommentFragmentIfVisible(false);
if (numAnswersDisplayed < question.answerCount && numAnswersDisplayed - position < 2) {
if (question.answers != null && question.answers.size() == numAnswersDisplayed && !serviceRunningForAnswers) {
setProgressBarIndeterminateVisibility(true);
startServiceForAnswers();
}
}
}
private void dismissPostCommentFragmentIfVisible(boolean finish) {
if (postCommentFragment != null) {
postCommentFragment.hideSoftKeyboard();
if (!finish) commentsDraft.put(postCommentFragment.getTag(), postCommentFragment.getCurrentText());
getFragmentManager().popBackStackImmediate();
postCommentFragment = null;
}
}
@SuppressWarnings("unchecked")
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case QuestionDetailsIntentService.RESULT_CODE_Q_CACHED:
setProgressBarIndeterminateVisibility(false);
case QuestionDetailsIntentService.RESULT_CODE_Q:
question = (Question) resultData.getSerializable(StringConstants.QUESTION);
displayQuestion();
if (question.answerCount > 0 && (question.answers == null || question.answers.isEmpty())) startServiceForAnswers();
else setProgressBarIndeterminateVisibility(false);
break;
case QuestionDetailsIntentService.RESULT_CODE_Q_BODY:
questionFragment.displayBody(resultData.getString(StringConstants.BODY));
if (question.answerCount == 0) setProgressBarIndeterminateVisibility(false);
break;
case QuestionDetailsIntentService.RESULT_CODE_Q_COMMENTS:
question.comments = (ArrayList<Comment>) resultData.getSerializable(StringConstants.COMMENTS);
questionFragment.setComments(question.comments);
break;
case QuestionDetailsIntentService.RESULT_CODE_ANSWERS:
serviceRunningForAnswers = false;
setProgressBarIndeterminateVisibility(false);
displayAnswers((ArrayList<Answer>) resultData.getSerializable(StringConstants.ANSWERS), true);
break;
case WriteIntentService.ACTION_ADD_COMMENT:
dismissPostCommentFragmentIfVisible(true);
addMyCommentToPost(resultData);
break;
case QuestionDetailsIntentService.RESULT_CODE_FAVORITE_SUCCESS:
serviceRunningForFavorite = false;
question.favorited = true;
setupFavoriteActionBarIcon();
break;
case QuestionDetailsIntentService.RESULT_CODE_FAVORITE_UNDO_SUCCESS:
serviceRunningForFavorite = false;
question.favorited = false;
setupFavoriteActionBarIcon();
break;
case QuestionDetailsIntentService.ERROR:
if (serviceRunningForAnswers) serviceRunningForAnswers = false;
if (serviceRunningForFavorite) serviceRunningForFavorite = false;
handleError(resultData);
break;
default:
break;
}
}
private void handleError(Bundle resultData) {
setProgressBarIndeterminateVisibility(false);
HttpException e = (HttpException) resultData.getSerializable(StringConstants.EXCEPTION);
int requestCode = resultData.getInt(StringConstants.REQUEST_CODE, -1);
if (requestCode == WriteIntentService.ACTION_ADD_COMMENT) {
PostCommentFragment lastPostCommentFragment = findFragmentByTag("postCommentFragment", PostCommentFragment.class);
if (lastPostCommentFragment != null) lastPostCommentFragment.setSendError(e.getErrorResponse());
else if (postCommentFragment != null) postCommentFragment.setSendError(e.getErrorResponse());
} else AppUtils.getErrorView(this, e);
}
protected void addMyCommentToPost(Bundle resultData) {
SharedPreferencesUtil.setLong(this, WritePermission.PREF_LAST_COMMENT_WRITE, System.currentTimeMillis());
Comment comment = (Comment) resultData.getSerializable(StringConstants.COMMENT);
int viewPagerPosition = resultData.getInt(StringConstants.VIEW_PAGER_POSITION, -1);
if (viewPagerPosition == 0) {
if (question.comments == null) question.comments = new ArrayList<Comment>();
question.comments.add(comment);
questionFragment.setComments(question.comments);
} else {
AnswerFragment answerFragment =
findFragmentByTag(getViewPagerFragmentTag(viewPagerPosition), AnswerFragment.class);
answerFragment.onCommentAdd(comment);
}
}
private void startServiceForAnswers() {
Intent intent = new Intent(this, QuestionDetailsIntentService.class);
intent.setAction(StringConstants.ANSWERS);
intent.putExtra(StringConstants.ACTION, QuestionDetailsIntentService.QA);
intent.putExtra(StringConstants.RESULT_RECEIVER, resultReceiver);
intent.putExtra(StringConstants.SITE, getIntent().getStringExtra(StringConstants.SITE));
intent.putExtra(StringConstants.QUESTION_ID, question.id);
intent.putExtra(StringConstants.PAGE, getNextPageNumber());
startService(intent);
serviceRunningForAnswers = true;
}
private void displayQuestion() {
if (questionFragment == null) questionFragment = QuestionFragment.newFragment();
questionFragment.setAndDisplay(question);
titlePageIndicator.notifyDataSetChanged();
questionViewPageAdapter.notifyDataSetChanged();
}
private void displayAnswers(ArrayList<Answer> answers, boolean add) {
if (answers != null && !answers.isEmpty()) {
if (question.answers == null) question.answers = new ArrayList<Answer>();
if (add && !StringConstants.QUESTION_ID.equals(getIntent().getAction())) question.answers.addAll(answers);
titlePageIndicator.notifyDataSetChanged();
questionViewPageAdapter.notifyDataSetChanged();
}
}
private int getNextPageNumber() {
int numAnswersDisplayed = questionViewPageAdapter.getCount() - 1;
return (numAnswersDisplayed / 10) + 1;
}
@Override
public void selectQuestionPage() {
if (viewPager != null && viewPager.getAdapter().getCount() > 0) {
final int currentItem = viewPager.getCurrentItem();
questionFragment.enableNavigationBack(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewPager.setCurrentItem(currentItem);
}
});
viewPager.setCurrentItem(0);
}
}
private String getViewPagerFragmentTag(int position) {
return "android:switcher:" + R.id.viewPager + ":" + position;
}
@Override
public void onShowComments() {
if (viewPager.getCurrentItem() == 0) prepareCommentFragment(question.id, question.comments);
else {
Answer answer = question.answers.get(viewPager.getCurrentItem() - 1);
prepareCommentFragment(answer.id, answer.comments);
}
}
private void prepareCommentFragment(long postId, ArrayList<Comment> comments) {
if (comments != null && !comments.isEmpty()) showCommentFragment(postId, comments);
else Toast.makeText(this, "No comments", Toast.LENGTH_SHORT).show();
}
private void showCommentFragment(long postId, ArrayList<Comment> comments) {
String fragmentTag = postId + "-" + StringConstants.COMMENTS;
commentFragment = findFragmentByTag(fragmentTag, CommentFragment.class);
if (commentFragment == null) {
commentFragment = new CommentFragment();
commentFragment.setComments(comments);
commentFragment.setResultReceiver(resultReceiver);
String currentViewPagerFragmentTag = "android:switcher:" + R.id.viewPager + ":" + viewPager.getCurrentItem();
OnCommentChangeListener onCommentChangeListener =
(OnCommentChangeListener) getFragmentManager().findFragmentByTag(currentViewPagerFragmentTag);
if (onCommentChangeListener != null) commentFragment.setOnCommentChangeListener(onCommentChangeListener);
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, commentFragment, fragmentTag);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.addToBackStack(fragmentTag);
transaction.commit();
}
}