package ryan.org.wordpress.android; import ryan.com.commonsware.cwac.cache.SimpleWebImageCache; import ryan.com.commonsware.cwac.thumbnail.ThumbnailAdapter; import ryan.com.commonsware.cwac.thumbnail.ThumbnailBus; import ryan.com.commonsware.cwac.thumbnail.ThumbnailMessage; import ryan.org.wordpress.android.models.Blog; import ryan.org.wordpress.android.util.EscapeUtils; import ryan.org.wordpress.android.util.WPTitleBar; import ryan.org.xmlrpc.android.XMLRPCClient; import ryan.org.xmlrpc.android.XMLRPCException; import ryan.org.xmlrpc.android.XMLRPCFault; import android.app.AlertDialog; import android.app.Dialog; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; import android.view.View.OnCreateContextMenuListener; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.LayoutAnimationController; import android.view.animation.TranslateAnimation; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewSwitcher; import android.widget.AdapterView.OnItemClickListener; import java.math.BigInteger; import java.net.URI; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.TimeZone; import java.util.Vector; import ryan.org.wordpress.android.R; public class ViewComments extends ListActivity { private static final int[] IMAGE_IDS={R.id.avatar}; private ThumbnailAdapter thumbs=null; private ArrayList<CommentEntry> model=null; private XMLRPCClient client; private String accountName = "", moderateErrorMsg = "", selectedPostID = ""; public Object[] origComments; public int[] changedStatuses; public HashMap<String, HashMap<?, ?>> allComments = new HashMap<String, HashMap<?, ?>>(); public int ID_DIALOG_MODERATING = 1; public int ID_DIALOG_REPLYING = 2; public int ID_DIALOG_DELETING = 3; public boolean initializing = true; public int selectedID = 0; public int rowID = 0, id; public ProgressDialog pd; private ViewSwitcher switcher; private int numRecords = 0; boolean loadMore = false; int totalComments = 0; int commentsToLoad = 30; private Vector<String> checkedComments; private int checkedCommentTotal = 0; private boolean inModeration = false; private Blog blog; private WPTitleBar titleBar; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.moderatecomments); boolean fromNotification = false; Bundle extras = getIntent().getExtras(); if(extras !=null) { id = WordPress.currentBlog.getId(); blog = new Blog(id, this); pd = new ProgressDialog(this); fromNotification = extras.getBoolean("fromNotification", false); } titleBar = (WPTitleBar) findViewById(R.id.actionBar); titleBar.refreshButton.setOnClickListener(new ImageButton.OnClickListener() { public void onClick(View v) { titleBar.startRotatingRefreshIcon(); refreshComments(false, false, false); } }); //create the ViewSwitcher in the current context switcher = new ViewSwitcher(this); Button footer = (Button)View.inflate(this, R.layout.list_footer_btn, null); footer.setText(getResources().getText(R.string.load_more) + " " + getResources().getText(R.string.tab_comments)); footer.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { switcher.showNext(); refreshComments(true, false, false); } }); View progress = View.inflate(this, R.layout.list_footer_progress, null); switcher.addView(footer); switcher.addView(progress); if (fromNotification) //dismiss the notification { //NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); //nm.cancel(22 + Integer.valueOf(id)); //loadComments(false, false); } this.setTitle(accountName + " - Moderate Comments"); boolean loadedComments = loadComments(false, false); if (!loadedComments){ refreshComments(false, false, false); } /*Button bulkEdit = (Button) findViewById(R.id.bulkEdit); bulkEdit.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { inModeration = !inModeration; showOrHideBulkCheckBoxes(); } });*/ Button deleteComments = (Button) findViewById(R.id.deleteComment); deleteComments.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { showDialog(ID_DIALOG_DELETING); new Thread() { public void run() { Looper.prepare(); deleteComments(); } }.start(); } }); Button approveComments = (Button) findViewById(R.id.approveComment); approveComments.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); moderateComments("approve"); } }.start(); } }); Button unapproveComments = (Button) findViewById(R.id.unapproveComment); unapproveComments.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); moderateComments("hold"); } }.start(); } }); Button spamComments = (Button) findViewById(R.id.markSpam); spamComments.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); moderateComments("spam"); } }.start(); } }); } protected void showOrHideBulkCheckBoxes() { ListView listView = getListView(); int loopMax = 0; if (listView.getFooterViewsCount() >= 1){ //we don't want a checkmark on the footer view if (listView.getLastVisiblePosition() == thumbs.getCount()){ loopMax = listView.getChildCount() - 1; } else{ loopMax = listView.getChildCount(); } } else{ loopMax = listView.getChildCount(); } for (int i=0; i < loopMax;i++){ RelativeLayout rl = (RelativeLayout) (View)listView.getChildAt(i).findViewById(R.id.bulkEditGroup); showBulkCheckBoxes(rl); /*if (inModeration){ showBulkCheckBoxes(rl); } else{ hideBulkCheckBoxes(rl); }*/ } } @SuppressWarnings("unchecked") protected void moderateComments(String newStatus) { //handles bulk moderation WordPressDB db = new WordPressDB(this); for (int i=0;i < checkedComments.size(); i++) { if (checkedComments.get(i).toString().equals("true")){ client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); CommentEntry listRow = (CommentEntry) getListView().getItemAtPosition(i); String curCommentID = listRow.commentID; HashMap contentHash, postHash = new HashMap(); contentHash = (HashMap) allComments.get(curCommentID); postHash.put("status", newStatus); postHash.put("content", contentHash.get("comment")); postHash.put("author", contentHash.get("author")); postHash.put("author_url", contentHash.get("url")); postHash.put("author_email", contentHash.get("email")); Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), curCommentID, postHash }; Object result = null; try { result = (Object) client.call("wp.editComment", params); boolean bResult = Boolean.parseBoolean(result.toString()); if (bResult){ checkedComments.set(i, "false"); listRow.status = newStatus; model.set(i, listRow); db.updateCommentStatus(ViewComments.this, id, listRow.commentID, newStatus); } } catch (XMLRPCException e) { moderateErrorMsg = e.getLocalizedMessage(); } } } dismissDialog(ID_DIALOG_MODERATING); Thread action = new Thread() { public void run() { if (moderateErrorMsg == ""){ Toast.makeText(ViewComments.this, getResources().getText(R.string.comments_moderated), Toast.LENGTH_SHORT).show(); } else{ //there was an xmlrpc error AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(moderateErrorMsg); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } } }; this.runOnUiThread(action); if (moderateErrorMsg == ""){ //no errors, refresh list checkedCommentTotal = 0; inModeration = false; Thread action2 = new Thread() { public void run() { pd = new ProgressDialog(ViewComments.this); // to avoid crash showOrHideBulkCheckBoxes(); hideModerationBar(); thumbs.notifyDataSetChanged(); } }; this.runOnUiThread(action2); } } protected void hideBulkCheckBoxes(RelativeLayout rl) { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(1.0f, 0.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f ); animation.setDuration(500); set.addAnimation(animation); rl.startAnimation(set); rl.setVisibility(View.GONE); if (checkedCommentTotal > 0){ hideModerationBar(); } } protected void showBulkCheckBoxes(RelativeLayout rl) { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(0.0f, 1.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 1.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f ); animation.setDuration(500); set.addAnimation(animation); rl.setVisibility(View.VISIBLE); rl.startAnimation(set); if (checkedCommentTotal > 0){ showModerationBar(); } } protected void deleteComments() { //bulk detete comments for (int i=0;i < checkedComments.size(); i++) { if (checkedComments.get(i).toString().equals("true")){ client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); CommentEntry listRow = (CommentEntry) getListView().getItemAtPosition(i); String curCommentID = listRow.commentID; Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), curCommentID }; try { client.call("wp.deleteComment", params); } catch (final XMLRPCException e) { moderateErrorMsg = e.getLocalizedMessage(); } } } dismissDialog(ID_DIALOG_DELETING); Thread action = new Thread() { public void run() { if (moderateErrorMsg == ""){ Toast.makeText(ViewComments.this, getResources().getText(R.string.comment_moderated), Toast.LENGTH_SHORT).show(); } else{ //error occured during delete request AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(moderateErrorMsg); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } } }; this.runOnUiThread(action); Thread action2 = new Thread() { public void run() { if (moderateErrorMsg == ""){ pd = new ProgressDialog(ViewComments.this); // to avoid crash refreshComments(false, true, true); } } }; this.runOnUiThread(action2); checkedCommentTotal = 0; inModeration = false; } @SuppressWarnings("unchecked") private boolean loadComments(boolean addMore, boolean refreshOnly) { WordPressDB postStoreDB = new WordPressDB(this); String author, postID, commentID, comment, dateCreatedFormatted, status, authorEmail, authorURL, postTitle; if (!addMore){ Vector<?> loadedPosts = postStoreDB.loadComments(ViewComments.this, id); if (loadedPosts != null){ HashMap<Object, Object> countHash = new HashMap<Object, Object>(); countHash = (HashMap) loadedPosts.get(0); numRecords = Integer.parseInt(countHash.get("numRecords").toString()); if (refreshOnly){ if (model != null){ model.clear(); } } else{ model=new ArrayList<CommentEntry>(); } //fixes trac #72 (1.5 bug) int sdk_int = 0; try { sdk_int = Integer.valueOf(android.os.Build.VERSION.SDK); } catch (Exception e1) { sdk_int = 3; //assume they are on cupcake } checkedComments = new Vector(); for (int i=1; i < loadedPosts.size(); i++){ checkedComments.add(i-1, "false"); HashMap contentHash = (HashMap) loadedPosts.get(i); allComments.put(contentHash.get("commentID").toString(), contentHash); author = EscapeUtils.unescapeHtml(contentHash.get("author").toString()); commentID = contentHash.get("commentID").toString(); postID = contentHash.get("postID").toString(); comment = EscapeUtils.unescapeHtml(contentHash.get("comment").toString()); dateCreatedFormatted = contentHash.get("commentDateFormatted").toString(); status = contentHash.get("status").toString(); authorEmail = EscapeUtils.unescapeHtml(contentHash.get("email").toString()); authorURL = EscapeUtils.unescapeHtml(contentHash.get("url").toString()); postTitle = EscapeUtils.unescapeHtml(contentHash.get("postTitle").toString()); if (model == null){ model=new ArrayList<CommentEntry>(); } //add to model model.add(new CommentEntry(postID, commentID, author, dateCreatedFormatted, comment, status, postTitle, authorURL, authorEmail, URI.create("http://gravatar.com/avatar/" + getMd5Hash(authorEmail.trim()) + "?s=60&d=identicon"))); } if (!refreshOnly){ try { ThumbnailBus bus = new ThumbnailBus(); thumbs=new ThumbnailAdapter(this, new CommentAdapter(),new SimpleWebImageCache<ThumbnailBus, ThumbnailMessage>(null, null, 101, bus),IMAGE_IDS); } catch (Exception e1) { e1.printStackTrace(); } ListView listView = (ListView) findViewById(android.R.id.list); listView.removeFooterView(switcher); if (loadedPosts.size() >= 30){ listView.addFooterView(switcher); } setListAdapter(thumbs); listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { Intent intent = new Intent(ViewComments.this, ViewComment.class); //intent.putExtra("pageID", pageIDs[(int) arg3]); //intent.putExtra("postTitle", titles[(int) arg3]); intent.putExtra("id", id); intent.putExtra("accountName", accountName); intent.putExtra("comment", model.get((int) arg3).comment); intent.putExtra("name", model.get((int) arg3).name); intent.putExtra("email", model.get((int) arg3).authorEmail); intent.putExtra("url", model.get((int) arg3).authorURL); intent.putExtra("date", model.get((int) arg3).dateCreatedFormatted); intent.putExtra("status", model.get((int) arg3).status); intent.putExtra("comment_id", model.get((int) arg3).commentID); intent.putExtra("post_id", model.get((int) arg3).postID); intent.putExtra("position", position); startActivityForResult(intent, 1); } }); listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { AdapterView.AdapterContextMenuInfo info; try { info = (AdapterView.AdapterContextMenuInfo) menuInfo; } catch (ClassCastException e) { //Log.e(TAG, "bad menuInfo", e); return; } selectedID = info.targetView.getId(); rowID = info.position; selectedPostID = model.get(info.position).postID; menu.setHeaderTitle(getResources().getText(R.string.comment_actions)); menu.add(0, 0, 0, getResources().getText(R.string.mark_approved)); menu.add(0, 1, 0, getResources().getText(R.string.mark_unapproved)); menu.add(0, 2, 0, getResources().getText(R.string.mark_spam)); menu.add(0, 3, 0, getResources().getText(R.string.reply)); menu.add(0, 4, 0, getResources().getText(R.string.delete)); } }); } else{ thumbs.notifyDataSetChanged(); } return true; } else{ return false; } } else{ Vector latestComments = postStoreDB.loadMoreComments(ViewComments.this, id, commentsToLoad); if (latestComments != null){ numRecords += latestComments.size(); for (int i=latestComments.size(); i > 0; i--){ HashMap contentHash = (HashMap) latestComments.get(i-1); allComments.put(contentHash.get("commentID").toString(), contentHash); author = EscapeUtils.unescapeHtml(contentHash.get("author").toString()); commentID = contentHash.get("commentID").toString(); postID = contentHash.get("postID").toString(); comment = EscapeUtils.unescapeHtml(contentHash.get("comment").toString()); dateCreatedFormatted = contentHash.get("commentDateFormatted").toString(); status = contentHash.get("status").toString(); authorEmail = EscapeUtils.unescapeHtml(contentHash.get("email").toString()); authorURL = EscapeUtils.unescapeHtml(contentHash.get("url").toString()); postTitle = EscapeUtils.unescapeHtml(contentHash.get("postTitle").toString()); //add to model model.add(new CommentEntry(postID, commentID, author, dateCreatedFormatted, comment, status, postTitle, authorURL, authorEmail, URI.create("http://gravatar.com/avatar/" + getMd5Hash(authorEmail.trim()) + "?s=60&d=identicon"))); } thumbs.notifyDataSetChanged(); } return true; } } @SuppressWarnings("unchecked") public void refreshComments(final boolean loadMore, final boolean refreshOnly, final boolean doInBackground) { if (!loadMore && !doInBackground){ showProgressBar(); } client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); HashMap hPost = new HashMap(); hPost.put("status", ""); hPost.put("post_id", ""); if (loadMore){ hPost.put("offset", numRecords); } if (totalComments != 0 && ((totalComments - numRecords) < 30)){ commentsToLoad = totalComments - numRecords; hPost.put("number", commentsToLoad); } else{ hPost.put("number", 30); } XMLRPCMethod method = new XMLRPCMethod("wp.getComments", new XMLRPCMethodCallback() { public void callFinished(Object[] result) { if (result.length == 0){ // no comments found if (pd.isShowing()) { pd.dismiss(); } titleBar.stopRotatingRefreshIcon(); } else{ origComments = result; String author, postID, commentID, comment, dateCreated, dateCreatedFormatted, status, authorEmail, authorURL, postTitle; HashMap contentHash = new HashMap(); Vector dbVector = new Vector(); Date d = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy"); Calendar cal = Calendar.getInstance(); TimeZone tz = cal.getTimeZone(); String shortDisplayName = ""; shortDisplayName = tz.getDisplayName(true, TimeZone.SHORT); if (result.length < 30){ //end of list reached getListView().removeFooterView(switcher); } //loop this! for (int ctr = 0; ctr < result.length; ctr++){ if (loadMore){ checkedComments.add("false"); } HashMap<String, String> dbValues = new HashMap(); contentHash = (HashMap) result[ctr]; allComments.put(contentHash.get("comment_id").toString(), contentHash); comment = contentHash.get("content").toString(); author = contentHash.get("author").toString(); status = contentHash.get("status").toString(); postID = contentHash.get("post_id").toString(); commentID = contentHash.get("comment_id").toString(); dateCreated = contentHash.get("date_created_gmt").toString(); authorURL = contentHash.get("author_url").toString(); authorEmail = contentHash.get("author_email").toString(); postTitle = contentHash.get("post_title").toString(); //make the date pretty String cDate = dateCreated.replace(tz.getID(), shortDisplayName); try{ d = sdf.parse(cDate); SimpleDateFormat sdfOut = new SimpleDateFormat("MMMM dd, yyyy hh:mm a"); dateCreatedFormatted = sdfOut.format(d); } catch (ParseException pe){ pe.printStackTrace(); dateCreatedFormatted = dateCreated; //just make it the ugly date if it doesn't work } dbValues.put("blogID", String.valueOf(id)); dbValues.put("postID", postID); dbValues.put("commentID", commentID); dbValues.put("author", author); dbValues.put("comment", comment); dbValues.put("commentDate", dateCreated); dbValues.put("commentDateFormatted", dateCreatedFormatted); dbValues.put("status", status); dbValues.put("url", authorURL); dbValues.put("email", authorEmail); dbValues.put("postTitle", postTitle); dbVector.add(ctr, dbValues); } WordPressDB postStoreDB = new WordPressDB(ViewComments.this); postStoreDB.saveComments(ViewComments.this, dbVector, loadMore); if (!doInBackground){ loadComments(loadMore, refreshOnly); } if (pd.isShowing()) { pd.dismiss(); } titleBar.stopRotatingRefreshIcon(); } if (!loadMore && !doInBackground){ closeProgressBar(); } else if (loadMore){ switcher.showPrevious(); } } }); Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), hPost }; method.call(params); } public void showProgressBar() { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(0.0f, 1.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,Animation.RELATIVE_TO_SELF, 0.0f ); animation.setDuration(500); set.addAnimation(animation); LayoutAnimationController controller = new LayoutAnimationController(set, 0.5f); RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); loading.setVisibility(View.VISIBLE); loading.setLayoutAnimation(controller); } public void closeProgressBar() { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(1.0f, 0.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, -1.0f ); animation.setDuration(500); set.addAnimation(animation); RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); loading.startAnimation(set); loading.setVisibility(View.INVISIBLE); } @Override public void onDestroy() { super.onDestroy(); } @Override public Object onRetainNonConfigurationInstance() { return(model); } private void goBlooey(Throwable t) { Log.e("WordPress", "Exception!", t); AlertDialog.Builder builder=new AlertDialog.Builder(this); builder .setTitle("Error") .setMessage(t.toString()) .setPositiveButton("OK", null) .show(); } class CommentEntry { String postID=""; String commentID=""; String name=""; String emailURL=""; String status=""; String comment=""; String postTitle=""; String authorURL=""; String authorEmail=""; String dateCreatedFormatted=""; URI profileImageUrl=null; CommentEntry(String postID, String commentID, String name, String dateCreatedFormatted, String comment, String status, String postTitle, String authorURL, String authorEmail, URI profileImageUrl) { this.postID=postID; this.commentID=commentID; this.name=name; this.emailURL=authorEmail; this.status=status; this.comment=comment; this.postTitle=postTitle; this.authorURL=authorURL; this.authorEmail=authorEmail; this.profileImageUrl=profileImageUrl; this.dateCreatedFormatted=dateCreatedFormatted; } } class CommentAdapter extends ArrayAdapter<CommentEntry> { CommentAdapter() { super(ViewComments.this, R.layout.row, model); } public View getView(int position, View convertView, ViewGroup parent) { View row=convertView; CommentEntryWrapper wrapper=null; if (row==null) { LayoutInflater inflater=getLayoutInflater(); row=inflater.inflate(R.layout.row, null); wrapper=new CommentEntryWrapper(row); row.setTag(wrapper); } else { wrapper=(CommentEntryWrapper)row.getTag(); } CommentEntry commentEntry = getItem(position); if("hold".equals(commentEntry.status)) row.setBackgroundDrawable(getResources().getDrawable(R.drawable.comment_pending_bg_selector)); else row.setBackgroundDrawable(getResources().getDrawable(R.drawable.list_bg_selector)); wrapper.populateFrom(commentEntry, position); return(row); } } class CommentEntryWrapper { private TextView name=null; private TextView emailURL=null; private TextView comment=null; private TextView status=null; private TextView postTitle=null; private ImageView avatar=null; private View row=null; private CheckBox bulkCheck=null; private RelativeLayout bulkEditGroup=null; CommentEntryWrapper(View row) { this.row=row; } void populateFrom(CommentEntry s, final int position) { getName().setText(s.name); String fEmailURL = s.authorURL; // use the required email address if the commenter didn't leave a url if (fEmailURL == ""){ fEmailURL = s.emailURL; } getEmailURL().setText(fEmailURL); getComment().setText(s.comment); getPostTitle().setText(getResources().getText(R.string.on) + " " + s.postTitle); row.setId(Integer.valueOf(s.commentID)); String prettyComment,textColor = ""; if (s.status.equals("spam")){ prettyComment = getResources().getText(R.string.spam).toString(); textColor = "#FF0000"; } else if (s.status.equals("hold")){ prettyComment = getResources().getText(R.string.unapproved).toString(); textColor = "#D54E21"; } else{ prettyComment = getResources().getText(R.string.approved).toString(); textColor = "#006505"; } getBulkEditGroup().setVisibility(View.VISIBLE); /*if (inModeration){ getBulkEditGroup().setVisibility(View.VISIBLE); } else{ getBulkEditGroup().setVisibility(View.GONE); }*/ getStatus().setText(prettyComment); getStatus().setTextColor(Color.parseColor(textColor)); getBulkCheck().setChecked(Boolean.parseBoolean(checkedComments.get(position).toString())); getBulkCheck().setTag(position); getBulkCheck().setOnClickListener(new OnClickListener() { public void onClick(View arg0) { checkedComments.set(position, String.valueOf(getBulkCheck().isChecked())); showOrHideModerateButtons(); } }); if (s.profileImageUrl!=null) { try { getAvatar().setImageResource(R.drawable.placeholder); getAvatar().setTag(s.profileImageUrl.toString()); } catch (Throwable t) { goBlooey(t); } } } TextView getName() { if (name==null) { name=(TextView)row.findViewById(R.id.name); } return(name); } TextView getEmailURL() { if (emailURL==null) { emailURL=(TextView)row.findViewById(R.id.email_url); } return(emailURL); } TextView getComment() { if (comment==null) { comment=(TextView)row.findViewById(R.id.comment); } return(comment); } TextView getStatus() { if (status==null) { status=(TextView)row.findViewById(R.id.status); } status.setTextSize(10); return(status); } TextView getPostTitle() { if (postTitle==null) { postTitle=(TextView)row.findViewById(R.id.postTitle); } return(postTitle); } ImageView getAvatar() { if (avatar==null) { avatar=(ImageView)row.findViewById(R.id.avatar); } return(avatar); } CheckBox getBulkCheck() { if (bulkCheck==null) { bulkCheck=(CheckBox)row.findViewById(R.id.bulkCheck); } return(bulkCheck); } RelativeLayout getBulkEditGroup() { if (bulkEditGroup==null) { bulkEditGroup=(RelativeLayout)row.findViewById(R.id.bulkEditGroup); } return(bulkEditGroup); } protected void showOrHideModerateButtons() { int previousTotal = checkedCommentTotal; checkedCommentTotal = 0; for (int i=0;i < checkedComments.size();i++){ if (checkedComments.get(i).equals("true")){ checkedCommentTotal++; } } if (checkedCommentTotal > 0 && previousTotal == 0){ showModerationBar(); } if (checkedCommentTotal == 0 && previousTotal > 0){ hideModerationBar(); } } } public static String getMd5Hash(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] messageDigest = md.digest(input.getBytes()); BigInteger number = new BigInteger(1,messageDigest); String md5 = number.toString(16); while (md5.length() < 32) md5 = "0" + md5; return md5; } catch(NoSuchAlgorithmException e) { Log.e("MD5", e.getLocalizedMessage()); return null; } } public void hideModerationBar() { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(1.0f, 0.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 1.0f ); animation.setDuration(500); set.addAnimation(animation); RelativeLayout moderationBar = (RelativeLayout) findViewById(R.id.moderationBar); moderationBar.clearAnimation(); moderationBar.startAnimation(set); moderationBar.setVisibility(View.INVISIBLE); } public void showModerationBar(){ AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(0.0f, 1.0f); animation.setDuration(500); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f,Animation.RELATIVE_TO_SELF, 0.0f ); animation.setDuration(500); set.addAnimation(animation); RelativeLayout moderationBar = (RelativeLayout) findViewById(R.id.moderationBar); moderationBar.setVisibility(View.VISIBLE); moderationBar.startAnimation(set); } interface XMLRPCMethodCallback { void callFinished(Object[] result); } class XMLRPCMethod extends Thread { private String method; private Object[] params; private Handler handler; private XMLRPCMethodCallback callBack; public XMLRPCMethod(String method, XMLRPCMethodCallback callBack) { this.method = method; this.callBack = callBack; handler = new Handler(); } public void call() { call(null); } public void call(Object[] params) { this.params = params; start(); } @SuppressWarnings("unchecked") @Override public void run() { try { //get the total comments HashMap<Object, Object> countResult = new HashMap<Object, Object>(); Object[] countParams = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), 0 }; try { countResult = (HashMap) client.call("wp.getCommentCount", countParams); totalComments = Integer.valueOf(countResult.get("awaiting_moderation").toString()) + Integer.valueOf(countResult.get("approved").toString()); } catch (XMLRPCException e) { e.printStackTrace(); } final Object[] result = (Object[]) client.call(method, params); handler.post(new Runnable() { public void run() { callBack.callFinished(result); } }); } catch (final XMLRPCFault e) { handler.post(new Runnable() { public void run() { if (pd.isShowing()) { pd.dismiss(); } titleBar.stopRotatingRefreshIcon(); closeProgressBar(); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); String msg = e.getLocalizedMessage(); dialogBuilder.setMessage(e.getFaultString()); if (msg.contains("403")){ dialogBuilder.setMessage(e.getFaultString() + " " + getResources().getString(R.string.load_settings)); dialogBuilder.setPositiveButton(getResources().getString(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { Intent i = new Intent(ViewComments.this, Settings.class); i.putExtra("id", id); i.putExtra("accountName", accountName); startActivity(i); } }); dialogBuilder.setNegativeButton(getResources().getString(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); } else{ dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); } dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }); } catch (final XMLRPCException e) { handler.post(new Runnable() { public void run() { if (pd.isShowing()) { pd.dismiss(); } titleBar.stopRotatingRefreshIcon(); closeProgressBar(); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getLocalizedMessage()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }); } } } interface XMLRPCMethodCallbackEditComment { void callFinished(Object result); } class XMLRPCMethodEditComment extends Thread { private String method; private Object[] params; private Handler handler; private XMLRPCMethodCallbackEditComment callBack; public XMLRPCMethodEditComment(String method, XMLRPCMethodCallbackEditComment callBack) { this.method = method; this.callBack = callBack; handler = new Handler(); } public void call() { call(null); } public void call(Object[] params) { this.params = params; start(); } @Override public void run() { try { final Object result = (Object) client.call(method, params); handler.post(new Runnable() { public void run() { callBack.callFinished(result); } }); } catch (final XMLRPCFault e) { handler.post(new Runnable() { public void run() { dismissDialog(ID_DIALOG_MODERATING); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getFaultString()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }); } catch (final XMLRPCException e) { handler.post(new Runnable() { public void run() { dismissDialog(ID_DIALOG_MODERATING); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getLocalizedMessage()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }); } } } @Override protected Dialog onCreateDialog(int id) { if(id == ID_DIALOG_MODERATING){ ProgressDialog loadingDialog = new ProgressDialog(this); if (checkedCommentTotal <= 1){ loadingDialog.setMessage(getResources().getText(R.string.moderating_comment)); } else{ loadingDialog.setMessage(getResources().getText(R.string.moderating_comments)); } loadingDialog.setIndeterminate(true); loadingDialog.setCancelable(false); return loadingDialog; } else if (id == ID_DIALOG_REPLYING){ ProgressDialog loadingDialog = new ProgressDialog(this); loadingDialog.setMessage(getResources().getText(R.string.replying_comment)); loadingDialog.setIndeterminate(true); loadingDialog.setCancelable(false); return loadingDialog; } else if (id == ID_DIALOG_DELETING){ ProgressDialog loadingDialog = new ProgressDialog(this); if (checkedCommentTotal <= 1){ loadingDialog.setMessage(getResources().getText(R.string.deleting_comment)); } else{ loadingDialog.setMessage(getResources().getText(R.string.deleting_comments)); } loadingDialog.setIndeterminate(true); loadingDialog.setCancelable(false); return loadingDialog; } return super.onCreateDialog(id); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public boolean onContextItemSelected(MenuItem item) { /* Switch on the ID of the item, to get what the user selected. */ switch (item.getItemId()) { case 0: showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); changeCommentStatus("approve", selectedID, rowID); } }.start(); return true; case 1: showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); changeCommentStatus("hold", selectedID, rowID); } }.start(); return true; case 2: showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); changeCommentStatus("spam", selectedID, rowID); } }.start(); return true; case 3: Intent i = new Intent(this, ReplyToComment.class); i.putExtra("commentID", selectedID); i.putExtra("accountName", accountName); i.putExtra("postID", selectedPostID); startActivityForResult(i, 0); return true; case 4: showDialog(ID_DIALOG_DELETING); new Thread() { public void run() { Looper.prepare(); deleteComment(selectedID); } }.start(); return true; } return false; } @SuppressWarnings("unchecked") private void changeCommentStatus(final String newStatus, final int selCommentID, int position) { //for individual comment moderation String sSelCommentID = String.valueOf(selCommentID); ListView lv = getListView(); CommentEntry ce = (CommentEntry)lv.getItemAtPosition(position); WordPressDB db = new WordPressDB(this); client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); HashMap contentHash, postHash = new HashMap(); contentHash = (HashMap) allComments.get(sSelCommentID); postHash.put("status", newStatus); postHash.put("content", contentHash.get("comment")); postHash.put("author", contentHash.get("author")); postHash.put("author_url", contentHash.get("url")); postHash.put("author_email", contentHash.get("email")); Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), sSelCommentID, postHash }; Object result = null; try { result = (Object) client.call("wp.editComment", params); boolean bResult = Boolean.parseBoolean(result.toString()); if (bResult){ ce.status = newStatus; model.set(position, ce); db.updateCommentStatus(ViewComments.this, id, ce.commentID, newStatus); } dismissDialog(ID_DIALOG_MODERATING); Thread action = new Thread() { public void run() { Toast.makeText(ViewComments.this, getResources().getText(R.string.comment_moderated), Toast.LENGTH_SHORT).show(); } }; this.runOnUiThread(action); Thread action2 = new Thread() { public void run() { thumbs.notifyDataSetChanged(); } }; this.runOnUiThread(action2); } catch (final XMLRPCException e) { dismissDialog(ID_DIALOG_MODERATING); Thread action3 = new Thread() { public void run() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getLocalizedMessage()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }; this.runOnUiThread(action3); } } private void deleteComment(final int selCommentID) { //delete individual comment client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), selCommentID }; try { client.call("wp.deleteComment", params); dismissDialog(ID_DIALOG_DELETING); Thread action = new Thread() { public void run() { Toast.makeText(ViewComments.this, getResources().getText(R.string.comment_moderated), Toast.LENGTH_SHORT).show(); } }; this.runOnUiThread(action); Thread action2 = new Thread() { public void run() { pd = new ProgressDialog(ViewComments.this); // to avoid crash refreshComments(false, true, false); } }; this.runOnUiThread(action2); } catch (final XMLRPCException e) { dismissDialog(ID_DIALOG_DELETING); Thread action3 = new Thread() { public void run() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getLocalizedMessage()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }; this.runOnUiThread(action3); } } private void replyToComment(final String postID, final int commentID, final String comment) { //reply to individual comment Vector<Object> settings = new Vector<Object>(); client = new XMLRPCClient(blog.getUrl(), blog.getHttpuser(), blog.getHttppassword()); HashMap<String, Object> replyHash = new HashMap<String, Object>(); replyHash.put("comment_parent", commentID); replyHash.put("content", comment); replyHash.put("author", ""); replyHash.put("author_url", ""); replyHash.put("author_email", ""); Object[] params = { blog.getBlogId(), blog.getUsername(), blog.getPassword(), Integer.valueOf(postID), replyHash }; try { client.call("wp.newComment", params); dismissDialog(ID_DIALOG_REPLYING); Thread action = new Thread() { public void run() { Toast.makeText(ViewComments.this, getResources().getText(R.string.reply_added), Toast.LENGTH_SHORT).show(); } }; this.runOnUiThread(action); Thread action2 = new Thread() { public void run() { pd = new ProgressDialog(ViewComments.this); // to avoid crash refreshComments(false, true, false); } }; this.runOnUiThread(action2); } catch (final XMLRPCException e) { dismissDialog(ID_DIALOG_REPLYING); Thread action3 = new Thread() { public void run() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ViewComments.this); dialogBuilder.setTitle(getResources().getText(R.string.connection_error)); dialogBuilder.setMessage(e.getLocalizedMessage()); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Just close the window. } }); dialogBuilder.setCancelable(true); if (!isFinishing()){ dialogBuilder.create().show(); } } }; this.runOnUiThread(action3); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (data != null) { Bundle extras = data.getExtras(); switch(requestCode) { case 0: final String returnText = extras.getString("replyText"); if (!returnText.equals("CANCEL")){ final String postID = extras.getString("postID"); final int commentID = extras.getInt("commentID"); showDialog(ID_DIALOG_REPLYING); new Thread(new Runnable(){ public void run(){ Looper.prepare(); pd = new ProgressDialog(ViewComments.this); // to avoid crash replyToComment(postID, commentID, returnText); } }).start(); } break; case 1: if (resultCode == RESULT_OK){ String comment_id; final String action; comment_id = extras.getString("comment_id"); final int position = extras.getInt("position"); action = extras.getString("action"); if (action.equals("approve") || action.equals("hold") || action.equals("spam")){ final int commentID = Integer.parseInt(comment_id); showDialog(ID_DIALOG_MODERATING); new Thread() { public void run() { Looper.prepare(); changeCommentStatus(action, commentID, position); } }.start(); } else if (action.equals("delete")){ final int commentID_del = Integer.parseInt(comment_id); showDialog(ID_DIALOG_DELETING); new Thread() { public void run() { deleteComment(commentID_del); } }.start(); } else if (action.equals("reply")){ Intent i = new Intent(this, ReplyToComment.class); i.putExtra("commentID", Integer.parseInt(comment_id)); i.putExtra("accountName", accountName); i.putExtra("postID", extras.getString("post_id")); startActivityForResult(i, 0); } } break; } } } }