QuestionActivity.java :  » Web » droidstack » org » droidstack » activity » Android Open Source

Android Open Source » Web » droidstack 
droidstack » org » droidstack » activity » QuestionActivity.java
package org.droidstack.activity;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import net.sf.jtpl.Template;
import net.sf.stackwrap4j.StackWrapper;
import net.sf.stackwrap4j.entities.Answer;
import net.sf.stackwrap4j.entities.Comment;
import net.sf.stackwrap4j.entities.Question;
import net.sf.stackwrap4j.entities.User;
import net.sf.stackwrap4j.http.HttpClient;
import net.sf.stackwrap4j.query.AnswerQuery;
import net.sf.stackwrap4j.query.QuestionQuery;
import net.sf.stackwrap4j.utils.StackUtils;

import org.droidstack.R;
import org.droidstack.util.Const;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;

public class QuestionActivity extends Activity {
  
  private static final String API_PREFIX = "api.";
  
  private int mQuestionID;
  private int mAnswerID;
  private String mEndpoint;
  private String mTemplate;
  private int mAnswerCount;
  private int mCurAnswer = -1;
  private int mPage = 0;
  private int mPageSize;
  
  private StackWrapper mAPI;
  private Question mQuestion;
  private List<Answer> mAnswers;
  private SharedPreferences mPreferences;
  
  private WebView mWebView;
  private TextView mAnswerCountView;
  private TextView mAnswerLabel;
  private ImageButton mNextButton;
  private ImageButton mPreviousButton;
  private ProgressBar mProgress;
  
  private boolean isRequestOngoing = false;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.question);
    
    HttpClient.setTimeout(Const.NET_TIMEOUT);
    try {
      InputStream is = getAssets().open("question.html", AssetManager.ACCESS_BUFFER);
      StringBuilder builder = new StringBuilder();
      int b;
      while((b = is.read()) != -1) {
        builder.append((char)b);
      }
      mTemplate = builder.toString();
    }
    catch (Exception e) {
      Log.e(Const.TAG, "wtf asset load fail", e);
      finish();
    }
    Uri data = getIntent().getData();
    try {
      mQuestionID = Integer.parseInt(data.getQueryParameter("qid"));
    }
    catch (Exception e) { }
    try {
      mAnswerID = Integer.parseInt(data.getQueryParameter("aid"));
    }
    catch (Exception e) { }
    if (mQuestionID == 0 && mAnswerID == 0) {
      Log.e(Const.TAG, "ViewQuestion: qid/aid not specified");
      finish();
      return;
    }
    mEndpoint = data.getQueryParameter("endpoint");
    if (mEndpoint == null) {
      Log.e(Const.TAG, "ViewQuestion: endpoint not specified");
      finish();
      return;
    }
    
    prepareViews();
    
    // make the title scroll!
    // find the title TextView
    TextView title = (TextView) findViewById(android.R.id.title);
    // set the ellipsize mode to MARQUEE and make it scroll only once
    title.setEllipsize(TruncateAt.MARQUEE);
    title.setMarqueeRepeatLimit(1);
    // in order to start strolling, it has to be focusable and focused
    title.setFocusable(true);
    title.setFocusableInTouchMode(true);
    title.requestFocus();
    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    mPageSize = Const.getPageSize(this);
    mAPI = new StackWrapper(mEndpoint, Const.APIKEY);
    if (savedInstanceState == null) {
      mAnswers = new ArrayList<Answer>();
      setTitle(R.string.loading);
      new FetchQuestionTask().execute();
    }
    else {
      mQuestion = (Question) savedInstanceState.getSerializable("mQuestion");
      mAnswers = (ArrayList<Answer>) savedInstanceState.getSerializable("mAnswers");
      mCurAnswer = savedInstanceState.getInt("mCurAnswer");
      mPage = savedInstanceState.getInt("mPage");
      mAnswerCount = savedInstanceState.getInt("mAnswerCount");
      updateView();
    }
  }
  
  @Override
  public void onSaveInstanceState(Bundle outState) {
    outState.putSerializable("mQuestion", mQuestion);
    outState.putSerializable("mAnswers", (ArrayList<Answer>) mAnswers);
    outState.putInt("mCurAnswer", mCurAnswer);
    outState.putInt("mPage", mPage);
    outState.putInt("mAnswerCount", mAnswerCount);
  }
  
  private class DWebViewClient extends WebViewClient {
    
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
      startActivity(i);
      return true;
    }
    
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    if (isRequestOngoing) return false;
    getMenuInflater().inflate(R.menu.question, menu);
    try {
      Method emulateShiftHeld = WebView.class.getMethod("emulateShiftHeld", null);
    }
    catch (NoSuchMethodException e) {
      menu.findItem(R.id.menu_select).setEnabled(false);
    }
      return true;
  }
  
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    //HACK it would be better if api can provide a browsable URL
    //but right now it looks like it lacks the feature.
    String questionUrl = "http://" + Uri.parse(mEndpoint).getHost().replace(API_PREFIX, "");
    questionUrl += "/questions/" + mQuestion.getPostId();
    switch(item.getItemId()) {
    case R.id.menu_open:
      startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(questionUrl)));
      return true;
    case R.id.menu_share:
      Intent i = new Intent(Intent.ACTION_SEND);
      i.setType("text/plain");
      i.putExtra(Intent.EXTRA_SUBJECT, mQuestion.getTitle());
      i.putExtra(Intent.EXTRA_TEXT, questionUrl);
      startActivity(Intent.createChooser(i, getString(R.string.menu_share)));
      return true;
    case R.id.menu_select:
      mWebView.emulateShiftHeld();
      return true;
    }
    return false;
  }
  
  private void prepareViews() {
    mWebView = (WebView) findViewById(R.id.content);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setWebViewClient(new DWebViewClient());
    try {
      // try to enable caching, useful for avatars
      WebSettings.class.getMethod("setAppCacheEnabled", new Class[] { boolean.class }).invoke(mWebView.getSettings(), true);
      WebSettings.class.getMethod("setCacheMode", new Class[] { int.class }).invoke(mWebView.getSettings(), WebSettings.LOAD_CACHE_ELSE_NETWORK);
    }
    catch(Exception e) {
      // app cache not supported, must be < 2.1
      Log.i(Const.TAG, "Unable to enable WebView caching", e);
    }
    mAnswerCountView = (TextView) findViewById(R.id.answer_count);
    mAnswerLabel = (TextView) findViewById(R.id.answer_label);
    mNextButton = (ImageButton) findViewById(R.id.next);
    mPreviousButton = (ImageButton) findViewById(R.id.previous);
    mProgress = (ProgressBar) findViewById(R.id.progress);
  }
  
  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.question);
    prepareViews();
    if (!isRequestOngoing) updateView();
  }

  private void updateView() {
    setTitle(mQuestion.getTitle());
    
    if (mCurAnswer == -1) {
      Template tpl = new Template(mTemplate);
      tpl.assign("ENDPOINT", mEndpoint);
      try {
        for (Comment c: mQuestion.getComments()) {
          tpl.assign("CBODY", c.getBody());
          User owner = c.getOwner();
          if (owner == null) {
            tpl.assign("CAUTHOR", "?");
            tpl.assign("CAID", "0");
          }
          else {
            tpl.assign("CAUTHOR", owner.getDisplayName());
            tpl.assign("CAID", String.valueOf(owner.getId()));
          }
          tpl.assign("CSCORE", String.valueOf(c.getScore()));
          if (c.getScore() > 0) tpl.parse("main.post.comment.score");
          tpl.parse("main.post.comment");
        }
      }
      catch (Exception e) {
        Log.e(Const.TAG, "wtf Question.getComments() error", e);
        finish();
      }
      for (String tag: mQuestion.getTags()) {
        tpl.assign("TAG", tag);
        tpl.parse("main.post.tags.tag");
      }
      tpl.parse("main.post.tags");
      User owner = mQuestion.getOwner();
      tpl.assign("QBODY", mQuestion.getBody());
      tpl.assign("QSCORE", String.valueOf(mQuestion.getScore()));
      if (owner != null) {
        tpl.assign("QAHASH", String.valueOf(owner.getEmailHash()));
        tpl.assign("QANAME", owner.getDisplayName());
        tpl.assign("QAREP", StackUtils.formatRep(owner.getReputation()));
        tpl.assign("QAID", String.valueOf(owner.getId()));
      }
      else {
        tpl.assign("QAHASH", "unknown");
        tpl.assign("QANAME", "[unregistered]");
        tpl.assign("QAREP", "0");
        tpl.assign("QAID", "0");
      }
      tpl.assign("QWHEN", StackUtils.formatElapsedTime(mQuestion.getCreationDate()));
      tpl.parse("main.post");
      tpl.assign("FONTSIZE", mPreferences.getString(Const.PREF_FONTSIZE, Const.DEF_FONTSIZE));
      tpl.parse("main");
      mWebView.loadDataWithBaseURL("about:blank", tpl.out(), "text/html", "utf-8", null);
      if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        if (mAnswerCount == 1) mAnswerLabel.setText(R.string.answer);
        else mAnswerLabel.setText(R.string.answers);
        mAnswerCountView.setText(String.valueOf(mAnswerCount));
      }
      else {
        if (mAnswerCount == 1) mAnswerCountView.setText(mAnswerCount + " " + getString(R.string.answer));
        else mAnswerCountView.setText(mAnswerCount + " " + getString(R.string.answers));
      }
      
      mPreviousButton.setEnabled(false);
      mNextButton.setEnabled(false);
      if (mAnswerCount > 0) mNextButton.setEnabled(true);
    }
    else {
      Template tpl = new Template(mTemplate);
      tpl.assign("ENDPOINT", mEndpoint);
      Answer answer = mAnswers.get(mCurAnswer);
      try {
        for (Comment c: answer.getComments()) {
          tpl.assign("CBODY", c.getBody());
          User owner = c.getOwner();
          if (owner == null) {
            tpl.assign("CAUTHOR", "?");
            tpl.assign("CAID", "0");
          }
          else {
            tpl.assign("CAUTHOR", owner.getDisplayName());
            tpl.assign("CAID", String.valueOf(owner.getId()));
          }
          tpl.assign("CSCORE", String.valueOf(c.getScore()));
          if (c.getScore() > 0) tpl.parse("main.post.comment.score");
          tpl.parse("main.post.comment");
        }
      }
      catch (Exception e) {
        Log.e(Const.TAG, "wtf Answer.getComments() error", e);
      }
      User owner = answer.getOwner();
      tpl.assign("QBODY", answer.getBody());
      tpl.assign("QSCORE", String.valueOf(answer.getScore()));
      // String.valueOf is needed because getEmailHash() returns null sometimes 
      if (owner != null) {
        tpl.assign("QAHASH", String.valueOf(owner.getEmailHash()));
        tpl.assign("QANAME", owner.getDisplayName());
        tpl.assign("QAREP", StackUtils.formatRep(owner.getReputation()));
        tpl.assign("QAID", String.valueOf(owner.getId()));
      }
      else {
        tpl.assign("QAHASH", "unknown");
        tpl.assign("QANAME", "[unregistered]");
        tpl.assign("QAREP", "0");
        tpl.assign("QAID", "0");
      }
      tpl.assign("QWHEN", StackUtils.formatElapsedTime(answer.getCreationDate()));
      if (answer.isAccepted()) tpl.parse("main.post.accepted");
      tpl.parse("main.post");
      tpl.assign("FONTSIZE", mPreferences.getString(Const.PREF_FONTSIZE, Const.DEF_FONTSIZE));
      tpl.parse("main");
      mWebView.loadDataWithBaseURL("about:blank", tpl.out(), "text/html", "utf-8", null);
      
      mPreviousButton.setEnabled(false);
      mNextButton.setEnabled(false);
      if (mCurAnswer > -1) mPreviousButton.setEnabled(true);
      if (mCurAnswer < mAnswerCount-1) mNextButton.setEnabled(true);
      if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        if (mAnswerCount == 1) mAnswerLabel.setText(R.string.answer);
        else mAnswerLabel.setText(R.string.answers);
        mAnswerCountView.setText((mCurAnswer+1) + "\nof\n" + mAnswerCount);
      }
      else {
        mAnswerCountView.setText((mCurAnswer+1) + "/" + mAnswerCount);
      }
    }
  }
  
  public void changePost(View target) {
    switch(target.getId()) {
    case R.id.next:
      mCurAnswer++;
      if (mCurAnswer >= mAnswers.size()) {
        new FetchMoreAnswers().execute();
      }
      else {
        updateView();
      }
      break;
    case R.id.previous:
      mCurAnswer--;
      updateView();
      break;
    }
  }
  
  private class FetchQuestionTask extends AsyncTask<Void, Void, Void> {
    
    private Exception mException;
    
    @Override
    protected void onPreExecute() {
      isRequestOngoing = true;
      mPreviousButton.setEnabled(false);
      mNextButton.setEnabled(false);
      mProgress.setVisibility(View.VISIBLE);
    }
    
    @Override
    protected Void doInBackground(Void... params) {
      try {
        if (mQuestionID == 0) {
          AnswerQuery aq = new AnswerQuery();
          aq.setBody(false).setComments(false).setIds(mAnswerID);
          Answer a = mAPI.getAnswers(aq).get(0);
          mQuestionID = a.getQuestionId();
        }
        QuestionQuery query = new QuestionQuery();
        query.setBody(true).setComments(true).setAnswers(false).setIds(mQuestionID);
        mQuestion = mAPI.getQuestions(query).get(0);
        mAnswerCount = mQuestion.getAnswerCount();
      }
      catch (Exception e) {
        mException = e;
      }
      return null;
    }
    
    @Override
    protected void onPostExecute(Void result) {
      if (isFinishing()) return;
      isRequestOngoing = false;
      mProgress.setVisibility(View.GONE);
      if (mException != null) {
        new AlertDialog.Builder(QuestionActivity.this)
          .setTitle(R.string.title_error)
          .setMessage(R.string.question_fetch_error)
          .setCancelable(false)
          .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
              finish();
            }
          }).create().show();
        Log.e(Const.TAG, "Failed to get question", mException);
      }
      else {
        updateView();
      }
    }
    
  }
  
  private class FetchMoreAnswers extends AsyncTask<Void, Void, List<Answer>> {
    
    private Exception mException;
    
    @Override
    protected void onPreExecute() {
      isRequestOngoing = true;
      mPreviousButton.setEnabled(false);
      mNextButton.setEnabled(false);
      mProgress.setVisibility(View.VISIBLE);
    }
    
    @Override
    protected List<Answer> doInBackground(Void... params) {
      try {
        AnswerQuery query = new AnswerQuery();
        query.setBody(true).setComments(true).setIds(mQuestionID);
        query.setPageSize(mPageSize).setPage(++mPage);
        query.setSort(AnswerQuery.Sort.votes());
        return mAPI.getAnswersByQuestionId(query);
      }
      catch (Exception e) {
        mException = e;
      }
      return null;
    }
    
    @Override
    protected void onPostExecute(List<Answer> result) {
      if (isFinishing()) return;
      isRequestOngoing = false;
      mProgress.setVisibility(View.GONE);
      if (mException != null) {
        new AlertDialog.Builder(QuestionActivity.this)
          .setTitle(R.string.title_error)
          .setMessage(R.string.more_answers_error)
          .setNeutralButton(android.R.string.ok, null)
          .create().show();
        Log.e(Const.TAG, "Failed to get answers", mException);
        mPage--;
        mCurAnswer--;
      }
      else {
        mAnswers.addAll(result);
      }
      updateView();
    }
    
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.