diff --git a/clients/android/NewsBlur/res/layout/include_comment.xml b/clients/android/NewsBlur/res/layout/include_comment.xml
index f5b0b214c..9c6196938 100644
--- a/clients/android/NewsBlur/res/layout/include_comment.xml
+++ b/clients/android/NewsBlur/res/layout/include_comment.xml
@@ -133,15 +133,15 @@
-
-
\ No newline at end of file
+
diff --git a/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java b/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java
index 33949f10e..7818bcee2 100644
--- a/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java
+++ b/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java
@@ -323,6 +323,7 @@ public class BlurDatabaseHelper {
commentValues.add(comment.getValues());
for (Reply reply : comment.replies) {
reply.commentId = comment.id;
+ reply.id = reply.constructId();
replyValues.add(reply.getValues());
}
}
@@ -334,6 +335,7 @@ public class BlurDatabaseHelper {
commentValues.add(comment.getValues());
for (Reply reply : comment.replies) {
reply.commentId = comment.id;
+ reply.id = reply.constructId();
replyValues.add(reply.getValues());
}
}
@@ -346,6 +348,7 @@ public class BlurDatabaseHelper {
commentValues.add(comment.getValues());
for (Reply reply : comment.replies) {
reply.commentId = comment.id;
+ reply.id = reply.constructId();
replyValues.add(reply.getValues());
}
}
@@ -965,7 +968,7 @@ public class BlurDatabaseHelper {
public List getCommentReplies(String commentId) {
String[] selArgs = new String[] {commentId};
String selection = DatabaseConstants.REPLY_COMMENTID+ " = ?";
- Cursor c = dbRO.query(DatabaseConstants.REPLY_TABLE, DatabaseConstants.REPLY_COLUMNS, selection, selArgs, null, null, DatabaseConstants.REPLY_DATE + " DESC");
+ Cursor c = dbRO.query(DatabaseConstants.REPLY_TABLE, null, selection, selArgs, null, null, DatabaseConstants.REPLY_DATE + " ASC");
List replies = new ArrayList(c.getCount());
while (c.moveToNext()) {
replies.add(Reply.fromCursor(c));
@@ -974,6 +977,16 @@ public class BlurDatabaseHelper {
return replies;
}
+ public void replyToComment(String storyId, String feedId, String commentUserId, String replyText) {
+ Reply reply = new Reply();
+ reply.commentId = Comment.constructId(storyId, feedId, commentUserId);
+ reply.text = replyText;
+ reply.userId = PrefsUtils.getUserDetails(context).id;
+ reply.date = new Date();
+ reply.id = reply.constructId();
+ synchronized (RW_MUTEX) {dbRW.insertWithOnConflict(DatabaseConstants.REPLY_TABLE, null, reply.getValues(), SQLiteDatabase.CONFLICT_REPLACE);}
+ }
+
public static void closeQuietly(Cursor c) {
if (c == null) return;
try {c.close();} catch (Exception e) {;}
diff --git a/clients/android/NewsBlur/src/com/newsblur/database/DatabaseConstants.java b/clients/android/NewsBlur/src/com/newsblur/database/DatabaseConstants.java
index 44ae2d24b..fb83268d1 100644
--- a/clients/android/NewsBlur/src/com/newsblur/database/DatabaseConstants.java
+++ b/clients/android/NewsBlur/src/com/newsblur/database/DatabaseConstants.java
@@ -134,7 +134,8 @@ public class DatabaseConstants {
public static final String ACTION_UNSHARE = "unshare";
public static final String ACTION_LIKE_COMMENT = "like_comment";
public static final String ACTION_UNLIKE_COMMENT = "unlike_comment";
- public static final String ACTION_COMMENT = "comment";
+ public static final String ACTION_REPLY = "reply";
+ public static final String ACTION_COMMENT_TEXT = "comment_text";
public static final String ACTION_STORY_HASH = "story_hash";
public static final String ACTION_FEED_ID = "feed_id";
public static final String ACTION_INCLUDE_OLDER = "include_older";
@@ -275,7 +276,8 @@ public class DatabaseConstants {
ACTION_UNSHARE + INTEGER + " DEFAULT 0, " +
ACTION_LIKE_COMMENT + INTEGER + " DEFAULT 0, " +
ACTION_UNLIKE_COMMENT + INTEGER + " DEFAULT 0, " +
- ACTION_COMMENT + TEXT + ", " +
+ ACTION_REPLY + INTEGER + " DEFAULT 0, " +
+ ACTION_COMMENT_TEXT + TEXT + ", " +
ACTION_STORY_HASH + TEXT + ", " +
ACTION_FEED_ID + TEXT + ", " +
ACTION_INCLUDE_OLDER + INTEGER + ", " +
@@ -294,10 +296,6 @@ public class DatabaseConstants {
SOCIAL_FEED_ID, SOCIAL_FEED_USERNAME, SOCIAL_FEED_TITLE, SOCIAL_FEED_ICON, SOCIAL_FEED_POSITIVE_COUNT, SOCIAL_FEED_NEUTRAL_COUNT, SOCIAL_FEED_NEGATIVE_COUNT
};
- public static final String[] REPLY_COLUMNS = {
- REPLY_COMMENTID, REPLY_DATE, REPLY_ID, REPLY_SHORTDATE, REPLY_TEXT, REPLY_USERID
- };
-
public static final String SUM_STORY_TOTAL = "storyTotal";
private static String STORY_SUM_TOTAL = " CASE " +
"WHEN MAX(" + STORY_INTELLIGENCE_AUTHORS + "," + STORY_INTELLIGENCE_TAGS + "," + STORY_INTELLIGENCE_TITLE + ") > 0 " +
diff --git a/clients/android/NewsBlur/src/com/newsblur/domain/Comment.java b/clients/android/NewsBlur/src/com/newsblur/domain/Comment.java
index 89ad3bea7..86653cd44 100644
--- a/clients/android/NewsBlur/src/com/newsblur/domain/Comment.java
+++ b/clients/android/NewsBlur/src/com/newsblur/domain/Comment.java
@@ -76,7 +76,7 @@ public class Comment implements Serializable {
}
public static String constructId(String storyId, String feedId, String userId) {
- return TextUtils.concat(storyId, feedId, userId).toString();
+ return TextUtils.concat(feedId, storyId, userId).toString();
}
}
diff --git a/clients/android/NewsBlur/src/com/newsblur/domain/Reply.java b/clients/android/NewsBlur/src/com/newsblur/domain/Reply.java
index b3e9fca9f..a95ccbe4c 100644
--- a/clients/android/NewsBlur/src/com/newsblur/domain/Reply.java
+++ b/clients/android/NewsBlur/src/com/newsblur/domain/Reply.java
@@ -4,6 +4,7 @@ import java.util.Date;
import android.content.ContentValues;
import android.database.Cursor;
+import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
import com.newsblur.database.DatabaseConstants;
@@ -24,6 +25,7 @@ public class Reply {
@SerializedName("date")
public Date date;
+ // NB: this is the commentId that we generate, not the API one
public String commentId;
public ContentValues getValues() {
@@ -47,4 +49,9 @@ public class Reply {
reply.userId = cursor.getString(cursor.getColumnIndex(DatabaseConstants.REPLY_USERID));
return reply;
}
-}
\ No newline at end of file
+
+ // construct a string we can internally use as a PK
+ public String constructId() {
+ return TextUtils.concat(commentId, "_", Long.toString(date.getTime())).toString();
+ }
+}
diff --git a/clients/android/NewsBlur/src/com/newsblur/fragment/ReplyDialogFragment.java b/clients/android/NewsBlur/src/com/newsblur/fragment/ReplyDialogFragment.java
index ff9d257db..0f4e06e6e 100644
--- a/clients/android/NewsBlur/src/com/newsblur/fragment/ReplyDialogFragment.java
+++ b/clients/android/NewsBlur/src/com/newsblur/fragment/ReplyDialogFragment.java
@@ -15,6 +15,7 @@ import android.widget.Toast;
import com.newsblur.R;
import com.newsblur.domain.Story;
import com.newsblur.network.APIManager;
+import com.newsblur.util.FeedUtils;
public class ReplyDialogFragment extends DialogFragment {
@@ -25,9 +26,6 @@ public class ReplyDialogFragment extends DialogFragment {
private String commentUserId, commentUsername;
private Story story;
- private APIManager apiManager;
-
-
public static ReplyDialogFragment newInstance(final Story story, final String commentUserId, final String commentUsername) {
ReplyDialogFragment frag = new ReplyDialogFragment();
Bundle args = new Bundle();
@@ -40,17 +38,14 @@ public class ReplyDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
-
story = (Story) getArguments().getSerializable(STORY);
-
commentUserId = getArguments().getString(COMMENT_USER_ID);
commentUsername = getArguments().getString(COMMENT_USERNAME);
final Activity activity = getActivity();
- apiManager = new APIManager(activity);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- final String shareString = getResources().getString(R.string.reply_to);
+ String shareString = getResources().getString(R.string.reply_to);
builder.setTitle(String.format(shareString, getArguments().getString(COMMENT_USERNAME)));
LayoutInflater layoutInflater = LayoutInflater.from(activity);
@@ -61,23 +56,7 @@ public class ReplyDialogFragment extends DialogFragment {
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
-
- new AsyncTask() {
- @Override
- protected Boolean doInBackground(Void... arg) {
- return apiManager.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString());
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (result) {
- Toast.makeText(activity, R.string.replied, Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(activity, R.string.error_replying, Toast.LENGTH_LONG).show();
- }
- ReplyDialogFragment.this.dismiss();
- };
- }.execute();
+ FeedUtils.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString(), activity);
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
diff --git a/clients/android/NewsBlur/src/com/newsblur/fragment/SetupCommentSectionTask.java b/clients/android/NewsBlur/src/com/newsblur/fragment/SetupCommentSectionTask.java
index 441a0b30e..5e7b341ab 100644
--- a/clients/android/NewsBlur/src/com/newsblur/fragment/SetupCommentSectionTask.java
+++ b/clients/android/NewsBlur/src/com/newsblur/fragment/SetupCommentSectionTask.java
@@ -177,8 +177,10 @@ public class SetupCommentSectionTask extends AsyncTask {
replyUsername.setText(R.string.unknown_user);
}
- TextView replySharedDate = (TextView) replyView.findViewById(R.id.reply_shareddate);
- replySharedDate.setText(reply.shortDate + " ago");
+ if (reply.shortDate != null) {
+ TextView replySharedDate = (TextView) replyView.findViewById(R.id.reply_shareddate);
+ replySharedDate.setText(reply.shortDate + " ago");
+ }
((LinearLayout) commentView.findViewById(R.id.comment_replies_container)).addView(replyView);
}
diff --git a/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java b/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java
index 20cfc96dc..b0e455bf6 100644
--- a/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java
+++ b/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java
@@ -466,14 +466,14 @@ public class APIManager {
return response.getResponse(gson, NewsBlurResponse.class);
}
- public boolean replyToComment(String storyId, String storyFeedId, String commentUserId, String reply) {
+ public NewsBlurResponse replyToComment(String storyId, String storyFeedId, String commentUserId, String reply) {
ContentValues values = new ContentValues();
values.put(APIConstants.PARAMETER_STORYID, storyId);
values.put(APIConstants.PARAMETER_STORY_FEEDID, storyFeedId);
values.put(APIConstants.PARAMETER_COMMENT_USERID, commentUserId);
values.put(APIConstants.PARAMETER_REPLY_TEXT, reply);
- final APIResponse response = post(APIConstants.URL_REPLY_TO, values);
- return (!response.isError());
+ APIResponse response = post(APIConstants.URL_REPLY_TO, values);
+ return response.getResponse(gson, NewsBlurResponse.class);
}
public boolean addFeed(String feedUrl, String folderName) {
diff --git a/clients/android/NewsBlur/src/com/newsblur/serialization/DateStringTypeAdapter.java b/clients/android/NewsBlur/src/com/newsblur/serialization/DateStringTypeAdapter.java
index 9fb08cbb1..ed5333883 100644
--- a/clients/android/NewsBlur/src/com/newsblur/serialization/DateStringTypeAdapter.java
+++ b/clients/android/NewsBlur/src/com/newsblur/serialization/DateStringTypeAdapter.java
@@ -5,6 +5,7 @@ import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.TimeZone;
import android.text.TextUtils;
import android.util.Log;
@@ -15,8 +16,15 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class DateStringTypeAdapter implements JsonDeserializer {
- // 2012-07-23 02:43:02
- private final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ private final DateFormat df;
+
+ public DateStringTypeAdapter() {
+ // API sends dates like 2012-07-23 02:43:02
+ df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ // API doesn't indicate TZ, but it is UTC
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
@Override
public Date deserialize(JsonElement element, Type type, JsonDeserializationContext arg2) throws JsonParseException {
diff --git a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java
index a80c198c3..d5ba0e972 100644
--- a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java
+++ b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java
@@ -227,6 +227,14 @@ public class FeedUtils {
NbActivity.updateAllActivities(true);
triggerSync(context);
}
+
+ public static void replyToComment(String storyId, String feedId, String commentUserId, String replyText, Context context) {
+ ReadingAction ra = ReadingAction.replyToComment(storyId, feedId, commentUserId, replyText);
+ dbHelper.enqueueAction(ra);
+ ra.doLocal(dbHelper);
+ NbActivity.updateAllActivities(true);
+ triggerSync(context);
+ }
public static FeedSet feedSetFromFolderName(String folderName) {
return FeedSet.folder(folderName, getFeedIdsRecursive(folderName));
diff --git a/clients/android/NewsBlur/src/com/newsblur/util/ReadingAction.java b/clients/android/NewsBlur/src/com/newsblur/util/ReadingAction.java
index b4c875233..d371fe16d 100644
--- a/clients/android/NewsBlur/src/com/newsblur/util/ReadingAction.java
+++ b/clients/android/NewsBlur/src/com/newsblur/util/ReadingAction.java
@@ -33,7 +33,7 @@ public class ReadingAction {
private String storyId;
private String feedId;
private String sourceUserId;
- private String commentText;
+ private String commentReplyText; // used for both comments and replies
private String commentUserId;
private ReadingAction() {
@@ -77,14 +77,14 @@ public class ReadingAction {
return ra;
}
- public static ReadingAction shareStory(String hash, String storyId, String feedId, String sourceUserId, String commentText) {
+ public static ReadingAction shareStory(String hash, String storyId, String feedId, String sourceUserId, String commentReplyText) {
ReadingAction ra = new ReadingAction();
ra.type = ActionType.SHARE;
ra.storyHash = hash;
ra.storyId = storyId;
ra.feedId = feedId;
ra.sourceUserId = sourceUserId;
- ra.commentText = commentText;
+ ra.commentReplyText = commentReplyText;
return ra;
}
@@ -106,6 +106,16 @@ public class ReadingAction {
return ra;
}
+ public static ReadingAction replyToComment(String storyId, String feedId, String commentUserId, String commentReplyText) {
+ ReadingAction ra = new ReadingAction();
+ ra.type = ActionType.REPLY;
+ ra.storyId = storyId;
+ ra.commentUserId = commentUserId;
+ ra.feedId = feedId;
+ ra.commentReplyText = commentReplyText;
+ return ra;
+ }
+
public ContentValues toContentValues() {
ContentValues values = new ContentValues();
values.put(DatabaseConstants.ACTION_TIME, System.currentTimeMillis());
@@ -145,7 +155,7 @@ public class ReadingAction {
values.put(DatabaseConstants.ACTION_STORY_ID, storyId);
values.put(DatabaseConstants.ACTION_FEED_ID, feedId);
values.put(DatabaseConstants.ACTION_SOURCE_USER_ID, sourceUserId);
- values.put(DatabaseConstants.ACTION_COMMENT, commentText);
+ values.put(DatabaseConstants.ACTION_COMMENT_TEXT, commentReplyText);
break;
case LIKE_COMMENT:
@@ -162,6 +172,14 @@ public class ReadingAction {
values.put(DatabaseConstants.ACTION_COMMENT_ID, commentUserId);
break;
+ case REPLY:
+ values.put(DatabaseConstants.ACTION_REPLY, 1);
+ values.put(DatabaseConstants.ACTION_STORY_ID, storyId);
+ values.put(DatabaseConstants.ACTION_FEED_ID, feedId);
+ values.put(DatabaseConstants.ACTION_COMMENT_ID, commentUserId);
+ values.put(DatabaseConstants.ACTION_COMMENT_TEXT, commentReplyText);
+ break;
+
default:
throw new IllegalStateException("cannot serialise uknown type of action.");
@@ -202,7 +220,7 @@ public class ReadingAction {
ra.storyId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_STORY_ID));
ra.feedId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_FEED_ID));
ra.sourceUserId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_SOURCE_USER_ID));
- ra.commentText = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_COMMENT));
+ ra.commentReplyText = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_COMMENT_TEXT));
} else if (c.getInt(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_LIKE_COMMENT)) == 1) {
ra.type = ActionType.LIKE_COMMENT;
ra.storyId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_STORY_ID));
@@ -213,6 +231,12 @@ public class ReadingAction {
ra.storyId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_STORY_ID));
ra.feedId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_FEED_ID));
ra.commentUserId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_COMMENT_ID));
+ } else if (c.getInt(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_REPLY)) == 1) {
+ ra.type = ActionType.REPLY;
+ ra.storyId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_STORY_ID));
+ ra.feedId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_FEED_ID));
+ ra.commentUserId = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_COMMENT_ID));
+ ra.commentReplyText = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_COMMENT_TEXT));
} else {
throw new IllegalStateException("cannot deserialise uknown type of action.");
}
@@ -243,7 +267,7 @@ public class ReadingAction {
return apiManager.markStoryAsUnstarred(storyHash);
case SHARE:
- return apiManager.shareStory(storyId, feedId, commentText, sourceUserId);
+ return apiManager.shareStory(storyId, feedId, commentReplyText, sourceUserId);
case LIKE_COMMENT:
return apiManager.favouriteComment(storyId, commentUserId, feedId);
@@ -251,6 +275,9 @@ public class ReadingAction {
case UNLIKE_COMMENT:
return apiManager.unFavouriteComment(storyId, commentUserId, feedId);
+ case REPLY:
+ return apiManager.replyToComment(storyId, feedId, commentUserId, commentReplyText);
+
default:
}
@@ -286,8 +313,8 @@ public class ReadingAction {
case SHARE:
dbHelper.setStoryShared(storyHash);
- if (!TextUtils.isEmpty(commentText)) {
- dbHelper.insertUpdateComment(storyId, feedId, commentText);
+ if (!TextUtils.isEmpty(commentReplyText)) {
+ dbHelper.insertUpdateComment(storyId, feedId, commentReplyText);
}
break;
@@ -299,6 +326,10 @@ public class ReadingAction {
dbHelper.setCommentLiked(storyId, commentUserId, feedId, false);
break;
+ case REPLY:
+ dbHelper.replyToComment(storyId, feedId, commentUserId, commentReplyText);
+ break;
+
default:
// not all actions have these, which is fine
}