package com.geel9.facepunch.activities; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import com.actionbarsherlock.view.MenuInflater; import com.geel9.facepunch.APISession.AvatarCallback; import com.geel9.facepunch.APISession.Category; import com.geel9.facepunch.APISession.EditCallback; import com.geel9.facepunch.APISession.FPPost; import com.geel9.facepunch.misc.FPPostSection; import com.geel9.facepunch.misc.PostSplitter; import com.geel9.facepunch.APISession.FPThread; import com.geel9.facepunch.APISession.Forum; import com.geel9.facepunch.APISession.PostCallback; import com.geel9.facepunch.APISession.QuoteCallback; import com.geel9.facepunch.APISession.RateCallback; import com.geel9.facepunch.APISession.Rating; import com.geel9.facepunch.APISession.RatingPair; import com.geel9.facepunch.APISession.ReplyCallback; import com.geel9.facepunch.R.anim; import com.geel9.facepunch.R.id; import com.geel9.facepunch.R.layout; import com.geel9.facepunch.R.menu; import com.geel9.facepunch.R.string; import com.geel9.facepunch.APISession; import com.geel9.facepunch.R; import android.app.AlertDialog; import android.app.Dialog; import android.app.NotificationManager; import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.AnimationDrawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.telephony.TelephonyManager; import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.AttributeSet; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.webkit.WebView; import android.widget.Button; import android.widget.EditText; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; public class ThreadActivity extends FPActivity { // Used for restoring list private class State { FPPost[] posts; int scrollY; int page; int numPages; int threadID; String threadName; boolean locked; boolean showingDialog; boolean isEditDialog; FPPost editingPost; String dialogText; } private int currentPage = 1; private int numPages = 1; private int threadId = 1; private String threadName = ""; public boolean locked = false; private Handler populateHandler = new Handler(); private LinearLayout childToScrollTo = null; private boolean doingNew = false; private FPPost editingPost; private int scrollToDestination = 0; private String forumName = ""; private FPPost[] displayedPosts; private int numPopulated = 0; public boolean destroyed = false; AlertDialog alertDialog; AlertDialog alertDialogReply; @Override public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.threadmenu, menu); return super.onCreateOptionsMenu(menu); } @Override public void RemoveMenuItems(com.actionbarsherlock.view.Menu menu){ if(!api.loggedIn()){ menu.removeItem(R.id.itemReplyT); } super.RemoveMenuItems(menu); } @Override public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.itemNextT: if(currentPage < numPages) loadPage(++currentPage); break; case R.id.itemPrevT: if(currentPage > 1) loadPage(--currentPage); break; case R.id.itemJumpT: try{ onCreateDialog(0).show(); }catch(Exception e){ } break; case R.id.itemReplyT: if(!locked){ createReply("", false, null); } break; default: return super.onOptionsItemSelected(item); } return true; } @Override public void OnRefreshPressed(){ loadPage(currentPage); super.OnRefreshPressed(); } @Override public void OnLogout(){ loadPage(currentPage); super.OnLogout(); } @Override public void OnLogin(){ loadPage(currentPage); super.OnLogin(); } public void createReply(String replyText, final boolean editing, final FPPost post){ Context mContext = this; AlertDialog.Builder builder; editingPost = post; LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.reply_dialog, (ViewGroup) findViewById(R.id.layout_root)); builder = new AlertDialog.Builder(mContext); builder.setView(layout); builder.setInverseBackgroundForced(true); final EditText edit = (EditText) layout.findViewById(R.id.editTextReply); edit.setText(replyText); edit.setSelection(edit.getText().toString().length()); final Button reply = (Button) layout.findViewById(R.id.buttonReplyOkay); final Button cancel = (Button) layout.findViewById(R.id.buttonReplyCancel); if(editing) reply.setText("Edit"); reply.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) { final ProgressDialog replyDialog = ProgressDialog.show( ThreadActivity.this, "", "Please wait...", true ); replyDialog.show(); reply.setClickable(false); cancel.setClickable(false); if(editing){ api.edit(post, edit.getText().toString(), new EditCallback(){ public void onResult(boolean success) { HideKeyboard(edit.getWindowToken()); replyDialog.dismiss(); reply.setClickable(true); cancel.setClickable(true); if(success){ alertDialogReply.dismiss(); loadPage(currentPage); } else{ Toast.makeText(ThreadActivity.this, "Could not edit.", Toast.LENGTH_SHORT).show(); } } }); }else{ api.reply(edit.getText().toString(), threadId, new ReplyCallback(){ public void onResult(boolean success) { HideKeyboard(edit.getWindowToken()); replyDialog.dismiss(); reply.setClickable(true); cancel.setClickable(true); if(success){ alertDialogReply.dismiss(); currentPage = numPages; loadPage(-1); } else{ Toast.makeText(ThreadActivity.this, "Could not reply.", 2000).show(); } } }); } } }); cancel.setOnClickListener(new OnClickListener(){ public void onClick(View v) { HideKeyboard(edit.getWindowToken()); alertDialogReply.dismiss(); } }); alertDialogReply = builder.create(); alertDialogReply.show(); } @Override protected Dialog onCreateDialog(int id) { switch(id) { case 0: Context mContext = this; AlertDialog.Builder builder; LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.jump_dialog, (ViewGroup) findViewById(R.id.layout_root)); builder = new AlertDialog.Builder(mContext); builder.setView(layout); builder.setInverseBackgroundForced(true); TextView text = (TextView) layout.findViewById(R.id.textJump); text.setText("There " + ((numPages > 1) ? "are " : "is ") + String.valueOf(numPages) + " page" + ((numPages > 1) ? "s" : "") + "."); final EditText edit = (EditText) layout.findViewById(R.id.editTextJump); edit.setText(String.valueOf(currentPage)); edit.requestFocus(); edit.setSelected(true); edit.setSelection(edit.getText().toString().length()); Button jump = (Button) layout.findViewById(R.id.buttonJumpOkay); Button cancel = (Button) layout.findViewById(R.id.buttonJumpCancel); jump.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) { int pageTo; try{ pageTo = Integer.parseInt(edit.getText().toString()); }catch(Exception e){ pageTo = 1; } if(pageTo > numPages) pageTo = numPages; if(pageTo < 1) pageTo = 1; currentPage = pageTo; alertDialog.dismiss(); loadPage(pageTo); } }); cancel.setOnClickListener(new OnClickListener(){ public void onClick(View v) { alertDialog.dismiss(); } }); alertDialog = builder.create(); return alertDialog; default: return null; } } @Override public void onDestroy(){ populateHandler.removeCallbacks(doPopulation); populateHandler = null; destroyed = true; super.onDestroy(); } @Override public void onCreate( Bundle savedInstanceState ) { // Load layout super.onCreate( savedInstanceState ); setContentView( R.layout.threadview ); Uri data2 = getIntent().getData(); if (data2 != null) { String scheme = data2.getScheme(); String host = data2.getHost(); List<String> path = data2.getPathSegments(); int length = path.size(); if(length == 1){ finish(); return; } else if(length == 2){ //Thread, but no page! OH LAWDY currentPage = 1; threadId = Integer.parseInt(path.get(1)); } else if(length == 3){ //Thread AND a page? WITCHRAFT currentPage = Integer.parseInt(path.get(2)); threadId = Integer.parseInt(path.get(1)); } if(api.loggedIn()){ loadPage(currentPage); } else{ Intent i = new Intent().setClass(this, LoginActivity.class); i.putExtra("do", "thread"); i.putExtra("threadid", threadId); i.putExtra("threadpage", currentPage); startActivity(i); } return; } else{ //Restore forum list final State data = (State)getLastCustomNonConfigurationInstance(); if ( data != null ) { this.currentPage = data.page; this.threadName = data.threadName; this.numPages = data.numPages; this.locked = data.locked; ActionText(threadName); this.threadId = data.threadID; if(data.posts == null || data.posts.length == 0){ loadPage(currentPage); return; } populateList( data.posts ); scrollToDestination = data.scrollY; if(data.showingDialog){ //Recreate the edit/reply dialog. this.createReply(data.dialogText, data.isEditDialog, data.editingPost); } return; } CheckLoginState(); //Set header title Intent intent = getIntent(); threadName = intent.getStringExtra("threadName"); threadId = intent.getIntExtra("threadId", 0); numPages = intent.getIntExtra("numPages", 1); currentPage = intent.getIntExtra("threadPage", 1); if(currentPage == -1) doingNew = true; locked = intent.getBooleanExtra("locked", false); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.cancel(threadId); ActionText(threadName); loadPage(currentPage); } } // Save activity state @Override public Object onRetainCustomNonConfigurationInstance() { State data = new State(); data.posts = displayedPosts; data.scrollY = ( (ScrollView)findViewById( R.id.scrollViewThread ) ).getScrollY(); data.page = currentPage; data.threadID = threadId; data.numPages = numPages; data.threadName = threadName; data.locked = locked; data.showingDialog = alertDialogReply != null && alertDialogReply.isShowing(); data.isEditDialog = editingPost != null; data.editingPost = editingPost; data.dialogText = alertDialogReply != null ? ((EditText)alertDialogReply.findViewById(R.id.editTextReply)).getText().toString() : ""; return data; } private void loadPage(int page){ // Show loading spinner LayoutInflater inflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE ); final LinearLayout postList = (LinearLayout)findViewById( R.id.postList ); postList.removeAllViews(); final ImageView loaderImage = (ImageView)inflater.inflate( R.layout.loadingspinner, postList, false ); numPopulated = 0; applyLoadingIcon( loaderImage ); postList.addView( loaderImage ); postList.setGravity( Gravity.CENTER_VERTICAL ); api.listPosts(this, threadId, page, new APISession.PostCallback() { public void onResult(final boolean success, final FPPost[] posts, final String threadTitle, final int pages, final int curPage) { runOnUiThread(new Runnable(){ public void run() { postList.removeView(loaderImage); postList.setGravity(Gravity.NO_GRAVITY); if(success && posts != null && posts.length > 0){ threadName = threadTitle; numPages = pages; currentPage = curPage; ActionText(threadTitle); populateList(posts); } else { Toast.makeText(ThreadActivity.this, getString(R.string.threadLoadingFailed), Toast.LENGTH_LONG).show(); } } }); } }); } private void createPostViews(final ArrayList<FPPostSection> sections, final LinearLayout root, final LayoutInflater inflater, final boolean isLink){ runOnUiThread(new Runnable(){ public void run() { for(int i = 0; i < sections.size(); i++){ final FPPostSection section = sections.get(i); switch(section.postSection){ case LINK: final LinearLayout customViewLink = (LinearLayout)inflater.inflate(R.layout.customviewlink, root, false); try{ String linkHTML = section.getLinkHTML(); if(!linkHTML.contains("<img")){ linkHTML = linkHTML; } ArrayList<FPPostSection> linkSections = PostSplitter.splitPost(linkHTML); createPostViews(linkSections, customViewLink, inflater, true); customViewLink.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) { try{ String url = section.getLinkUrl(); Uri data2 = Uri.parse(url); boolean doSwitch = false; if (data2 != null) { String host = data2.getHost(); List<String> path = data2.getPathSegments(); int length = path.size(); if(length > 0 && host.contains("facepunch.com")){ String pathThread = path.get(0); if(pathThread.contains("thread")){ if(length == 2){ //Thread, but no page! OH LAWDY currentPage = 1; threadId = Integer.parseInt(path.get(1)); doSwitch = true; } else if(length == 3){ //Thread AND a page? WITCHRAFT currentPage = Integer.parseInt(path.get(2)); threadId = Integer.parseInt(path.get(1)); doSwitch = true; } } } } if(doSwitch){ loadPage(currentPage); } else if(!doSwitch){ Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); startActivity(i); } }catch(ActivityNotFoundException e){ } } }); root.addView(customViewLink); }catch(Exception e){ } break; case IMAGE: final LinearLayout customViewImage = (LinearLayout)inflater.inflate(R.layout.customviewimage, root, false); final ScrollView scroller = (ScrollView)findViewById(R.id.scrollViewThread); try{ final ImageView im = (ImageView)customViewImage.findViewById(R.id.imageViewCustom); final String url = section.getImgUrl(); if(showImages()){ im.setAdjustViewBounds(true); im.setImageResource( R.anim.loadingspinner ); final AnimationDrawable loadingAnimation = (AnimationDrawable)im.getDrawable(); im.post( new Runnable() { public void run() { loadingAnimation.start(); } } ); api.getImage(url, ThreadActivity.this, new AvatarCallback(){ public void onResult(boolean success, Bitmap avatar) { if(success){ try{ int height = avatar.getHeight(); int width = avatar.getWidth(); if(section.imageIsThumb){ im.setMaxHeight((int)(height * 0.35f)); im.setMaxWidth((int)(width * 0.35f)); } im.setImageBitmap(avatar); }catch(Exception e){im.setVisibility(View.GONE);} } else im.setVisibility(View.GONE); } }); if(showImages()) root.addView(customViewImage); } }catch(Exception e){ } break; case TEXT: final LinearLayout customView = (LinearLayout)inflater.inflate(R.layout.customviewtext, root, false); try{ TextView t = (TextView)customView.findViewById(R.id.textViewCustom); String text = section.getHTML(); if(isLink && !text.startsWith("<a")){ text = "<a href='http://www.walkthedinosaur.net'>" + text + "</a>"; } t.setText(Html.fromHtml(text)); t.setMovementMethod(LinkMovementMethod.getInstance()); root.addView(customView); }catch(Exception e){ } break; case QUOTE: final LinearLayout customViewQuote = (LinearLayout)inflater.inflate(R.layout.customviewquote, root, false); try{ String content = section.getQuoteContent(); String author = section.getQuoteAuthor(); TextView quoteAuthor = (TextView)customViewQuote.findViewById(R.id.textViewQuoteAuthor); quoteAuthor.setText(Html.fromHtml("Posted by " + author + ":")); if(author.equals("")){ quoteAuthor.setVisibility(View.GONE); } ArrayList<FPPostSection> quoteSections = PostSplitter.splitPost(content); createPostViews(quoteSections, customViewQuote, inflater, false); root.addView(customViewQuote); }catch(Exception e){ } break; case IFRAME: final LinearLayout customViewIframe = (LinearLayout)inflater.inflate(R.layout.customviewiframe, root, false); try{ final Button showIframeButton = (Button)customViewIframe.findViewById(R.id.buttonShowIframe); final WebView iFrame = (WebView)customViewIframe.findViewById(R.id.webViewIframe); showIframeButton.setOnClickListener(new OnClickListener(){ public void onClick(View v) { showIframeButton.setVisibility(View.GONE); iFrame.setVisibility(View.VISIBLE); String url = section.iFrameLink; iFrame.loadUrl(url); } }); }catch(Exception e){ Toast.makeText(ThreadActivity.this, "Exception in iframe: " + e.toString(), Toast.LENGTH_LONG).show(); } root.addView(customViewIframe); break; case MEDIA: final LinearLayout customViewMedia = (LinearLayout)inflater.inflate(R.layout.customviewiframe, root, false); try{ final Button showMediaButton = (Button)customViewMedia.findViewById(R.id.buttonShowIframe); final WebView iFrame = (WebView)customViewMedia.findViewById(R.id.webViewIframe); customViewMedia.removeView(iFrame); showMediaButton.setText("Go to " + section.mediaName); showMediaButton.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) { String url = section.mediaURL; Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); startActivity(i); } }); }catch(Exception e){ Toast.makeText(ThreadActivity.this, "Exception in media: " + e.toString(), Toast.LENGTH_LONG).show(); } root.addView(customViewMedia); break; case RELEASE: final LinearLayout customViewRelease = (LinearLayout)inflater.inflate(R.layout.customviewrelease, root, false); try{ String content = section.getHTML(); ArrayList<FPPostSection> releaseSections = PostSplitter.splitPost(content); createPostViews(releaseSections, customViewRelease, inflater, false); root.addView(customViewRelease); }catch(Exception e){ } } } } }); } @SuppressWarnings("unchecked") private void makeRatings(LinearLayout ratingsDiv, HorizontalScrollView scroll, LayoutInflater inflater, FPPost post){ ArrayList<RatingPair> rat = new ArrayList<RatingPair>(); for(int i = 0; i < Rating.values().length; i++){ Rating r = Rating.values()[i]; int numRating = post.getRatingCount(r); if(numRating > 0) { RatingPair rp = api.new RatingPair(); rp.rating = r; rp.numRatings = numRating; rat.add(rp); } } Collections.sort(rat); if(rat.size() > 0){ for(int i = 0; i < rat.size(); i++){ try{ RatingPair r = rat.get(i); String name = r.rating.toString().toLowerCase().replace(" ", "_"); LinearLayout rating = (LinearLayout)inflater.inflate(R.layout.rating, ratingsDiv, false); ImageView img = (ImageView)rating.findViewById(R.id.imageViewRating); TextView num = (TextView)rating.findViewById(R.id.textViewRatingName); num.setText("• " + r.numRatings); int resId = getResources().getIdentifier(name, "drawable", getPackageName()); img.setImageResource(resId); ratingsDiv.addView(rating); }catch(Exception e){ e = e; } } } else{ ratingsDiv.setVisibility(View.GONE); scroll.setVisibility(View.GONE); } } private Runnable doPopulation = new Runnable(){ public void run() { if(destroyed || populateHandler == null) return; final ScrollView scroller = (ScrollView)findViewById(R.id.scrollViewThread); LinearLayout root = (LinearLayout)findViewById(R.id.postList); if(numPopulated >= displayedPosts.length){ if(childToScrollTo != null && doingNew){ scroller.smoothScrollTo(0, childToScrollTo.getTop()); doingNew = false; childToScrollTo = null; } else if(childToScrollTo == null && doingNew){ LinearLayout holder = (LinearLayout)root.getChildAt(root.getChildCount() - 1); scroller.smoothScrollTo(0, holder.getTop()); doingNew = false; childToScrollTo = null; } else{ scroller.post( new Runnable() { public void run() { scroller.smoothScrollTo( 0, scrollToDestination ); } } ); } ((LinearLayout)findViewById(R.id.postAds)).removeAllViews(); DisplayAd((LinearLayout)findViewById(R.id.postAds)); return; } final FPPost p = displayedPosts[numPopulated]; final LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); final String postHTML = p.getMessageHTML(); int postList = R.layout.listpost_small; if(showWidescreen()) postList = R.layout.listpost; final LinearLayout postItem = (LinearLayout)inflater.inflate(postList, root, false); final LinearLayout ratings = (LinearLayout)postItem.findViewById(R.id.linearLayoutPostRatings); if(p.getNew() && childToScrollTo == null){ childToScrollTo = postItem; } //Android color format: (alpha << 24) | (r << 16) | (g << 8) | b int backColor = Color.WHITE; boolean switchColor = (numPopulated % 2) == 0; if(switchColor) backColor = (255 << 24) | (240 << 16) | (240 << 8) | 240; if(api.loggedIn() && p.getAuthor().getId() == api.bb_userid){ backColor = (255 << 24) | (255 << 16) | (255 << 8) | 200; } postItem.setBackgroundColor(backColor); postItem.setOnLongClickListener(new OnLongClickListener(){ public boolean onLongClick(View v) { //No use in doing anything if we're not logged in! if(!api.loggedIn()) return false; final CharSequence[] items; if(forumName.equals("Mass Debate")){ if(p.getAuthor().getName().toLowerCase().equals(api.username().toLowerCase())){ items = new CharSequence[]{ "Quote", "Edit" }; } else items = new CharSequence[]{ "Quote"}; } else{ FPPost po = p; APISession a = api; if(p.getAuthor().getName().toLowerCase().equals(api.username().toLowerCase())){ items = new CharSequence[]{ "Quote", "Edit" }; } else items = new CharSequence[]{ "Quote", "Rate"}; } new AlertDialog.Builder( ThreadActivity.this ) .setTitle( "Post actions" ) .setItems( items, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int item ) { // Quote if ( items[item].equals("Quote") ) { final ProgressDialog quoteDialog = ProgressDialog.show( ThreadActivity.this, "", "Loading quote...", true ); quoteDialog.show(); api.quote(p, new QuoteCallback(){ public void onResult(boolean success, String quote) { quoteDialog.dismiss(); if(success){ createReply(quote, false, null); } else Toast.makeText(ThreadActivity.this, "Could not load quote. Please try again.", Toast.LENGTH_SHORT).show(); } }); } //Rate else if(items[item].equals("Rate")){ Rating[] ratings = new Rating[p.ratingCodes.keySet().size()]; ratings = p.ratingCodes.keySet().toArray(ratings); ArrayList<String> optionList = new ArrayList<String>(); for(int i = 0; i < ratings.length; i++){ optionList.add(ratings[i].toString());} String[] options = new String[optionList.size()]; options = optionList.toArray(options); final Rating[] ratingsOptions = ratings; new AlertDialog.Builder( ThreadActivity.this ) .setTitle( "Rate post" ) .setItems( options, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item){ api.rate(p, ratingsOptions[item], new RateCallback(){ public void onResult(boolean success) { if(success){ Toast.makeText(ThreadActivity.this, "Rated successfully.", Toast.LENGTH_SHORT).show(); } else{ Toast.makeText(ThreadActivity.this, "Could not rate.", Toast.LENGTH_SHORT).show(); } } }); } }).create().show(); } //Edit else if(items[item].equals("Edit")){ final ProgressDialog quoteDialog = ProgressDialog.show( ThreadActivity.this, "", "Loading post...", true ); quoteDialog.show(); api.getEdit(p, new QuoteCallback(){ public void onResult(boolean success, String quote) { quoteDialog.dismiss(); if(success){ createReply(quote, true, p); } else Toast.makeText(ThreadActivity.this, "Could not load post. Please try again.", Toast.LENGTH_SHORT).show(); } }); } } } ) .create().show(); return true; } }); makeRatings(ratings, (HorizontalScrollView)postItem.findViewById(R.id.horizontalScrollViewRating), inflater, p); ((TextView)postItem.findViewById(R.id.textViewPostUsername2)).setText(Html.fromHtml(p.getAuthor().getStyledName())); TextView userTitle = (TextView)postItem.findViewById(R.id.textViewUserTitle); userTitle.setText(Html.fromHtml(p.getAuthor().userTitle)); if(p.getAuthor().userTitle.equals("")) userTitle.setVisibility(View.GONE); ((TextView)postItem.findViewById(R.id.textViewPostDate)).setText("Posted " + p.getDate()); ((TextView)postItem.findViewById(R.id.textViewPostPostcount)).setText(String.valueOf(p.getAuthor().getPostCount() + " posts")); final LinearLayout postContent = (LinearLayout)postItem.findViewById(R.id.layoutPostContent); api.getAvatar(p.getAuthor().getId(), ThreadActivity.this, showAvatars(), new APISession.AvatarCallback() { public void onResult(boolean success, Bitmap avatar) { if(success && avatar.getWidth() != -1 && avatar.getHeight() != -1){ if(cacheAvatars()) api.cacheAvatar(avatar, p.getAuthor().getId(), ThreadActivity.this); ((ImageView) postItem.findViewById(R.id.imageViewUserAvatar)).setImageBitmap(avatar); } } }); ArrayList<FPPostSection> sections = p.sections; try { if(p.sections.size() == 0) sections = PostSplitter.splitPost(postHTML); displayedPosts[numPopulated].sections = sections; createPostViews(sections, postContent, inflater, false); root.addView(postItem); numPopulated++; populateHandler.postDelayed(doPopulation, 10); } catch (Exception e){ Toast.makeText(ThreadActivity.this, "Post error: " + p.getMessageHTML() + "\nError: " + e.toString(), Toast.LENGTH_LONG).show(); numPopulated++; populateHandler.postDelayed(doPopulation, 10); } } }; private void populateList(FPPost[] posts){ if(populateHandler == null) return; displayedPosts = posts; populateHandler.postDelayed(doPopulation, 100); api.trimCache(this, cacheAvatarsSize()); } }