Use Executor to fetch removed comments.

This commit is contained in:
Alex Ning 2021-12-15 22:52:31 +08:00
parent f3b0a04f3c
commit 59fadbb0e0
5 changed files with 126 additions and 168 deletions

View File

@ -50,7 +50,7 @@ dependencies {
implementation 'androidx.biometric:biometric:1.2.0-alpha03'
implementation 'androidx.browser:browser:1.3.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
def lifecycleVersion = "2.3.1"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
@ -67,7 +67,7 @@ dependencies {
implementation "androidx.room:room-runtime:$roomVersion"
annotationProcessor "androidx.room:room-compiler:$roomVersion"
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
implementation 'androidx.work:work-runtime:2.5.0'
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'com.google.android.material:material:1.5.0-alpha05'
/** ExoPlayer **/
@ -94,7 +94,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
// Dependency injection
def daggerVersion = "2.34"
def daggerVersion = "2.38.1"
implementation "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"

View File

@ -1,74 +1,108 @@
package ml.docilealligator.infinityforreddit.comment;
import android.os.AsyncTask;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.concurrent.Executor;
import ml.docilealligator.infinityforreddit.apis.PushshiftAPI;
import ml.docilealligator.infinityforreddit.utils.JSONUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class FetchRemovedComment {
public static void fetchRemovedComment(Retrofit retrofit, Comment comment, FetchRemovedCommentListener listener) {
retrofit.create(PushshiftAPI.class).getRemovedComment(comment.getId())
.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseCommentAsyncTask(response.body(), comment, listener).execute();
public static void fetchRemovedComment(Executor executor, Handler handler, Retrofit retrofit, Comment comment,
FetchRemovedCommentListener listener) {
executor.execute(() -> {
try {
Response<String> response = retrofit.create(PushshiftAPI.class).getRemovedComment(comment.getId()).execute();
if (response.isSuccessful()) {
Comment removedComment = parseComment(response.body(), comment);
handler.post(() -> {
if (removedComment != null) {
listener.fetchSuccess(removedComment);
} else {
listener.fetchFailed();
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
t.printStackTrace();
listener.fetchFailed();
}
});
});
} else {
handler.post(listener::fetchFailed);
}
} catch (IOException e) {
e.printStackTrace();
handler.post(listener::fetchFailed);
}
});
}
// At the moment of writing this code, directly fetching a removed comment from
// Pushift.io API returns an Internal Server Error, so we temporarily do it this way instead.
// If this fails to return the removed comment, we try our luck with Reveddit API
public static void searchRemovedComment(Retrofit retrofit, Comment comment, FetchRemovedCommentListener listener) {
long after = (comment.getCommentTimeMillis() / 1000) - 1; // 1 second before comment creation epoch
retrofit.create(PushshiftAPI.class).searchComments(
comment.getLinkId(),
3000,
"asc",
"id,author,body",
after,
after + 43200, // 12 Hours later
"*")
.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseCommentAsyncTask(response.body(), comment, listener).execute();
public static void searchRemovedComment(Executor executor, Handler handler, Retrofit retrofit, Comment comment,
FetchRemovedCommentListener listener) {
executor.execute(() -> {
long after = (comment.getCommentTimeMillis() / 1000) - 1; // 1 second before comment creation epoch
try {
Response<String> response = retrofit.create(PushshiftAPI.class).searchComments(
comment.getLinkId(),
3000,
"asc",
"id,author,body",
after,
after + 43200, // 12 Hours later
"*").execute();
if (response.isSuccessful()) {
Comment removedComment = parseComment(response.body(), comment);
handler.post(() -> {
if (removedComment != null) {
listener.fetchSuccess(removedComment);
} else {
listener.fetchFailed();
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
t.printStackTrace();
listener.fetchFailed();
}
});
});
} else {
handler.post(listener::fetchFailed);
}
} catch (IOException e) {
e.printStackTrace();
handler.post(listener::fetchFailed);
}
});
}
@Nullable
private static Comment parseComment(String responseBody, Comment comment) {
try {
JSONArray commentJSONArray = new JSONObject(responseBody).getJSONArray(JSONUtils.DATA_KEY);
JSONObject commentFound = null;
for (int i = 0; i < commentJSONArray.length(); i++) {
JSONObject commentJSON = commentJSONArray.getJSONObject(i);
if (!commentJSON.isNull("id") && commentJSON.getString("id").equals(comment.getId())) {
commentFound = commentJSON;
break;
}
}
if (commentFound == null) {
return null;
}
return parseRemovedComment(commentFound, comment);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
@Nullable
private static Comment parseRemovedComment(@NonNull JSONObject result, Comment comment) throws JSONException {
String id = result.getString(JSONUtils.ID_KEY);
String author = result.getString(JSONUtils.AUTHOR_KEY);
@ -92,47 +126,4 @@ public class FetchRemovedComment {
void fetchFailed();
}
private static class ParseCommentAsyncTask extends AsyncTask<Void, Void, Void> {
private final String responseBody;
private final FetchRemovedCommentListener listener;
Comment comment;
public ParseCommentAsyncTask(String responseBody, Comment comment, FetchRemovedCommentListener listener) {
this.responseBody = responseBody;
this.comment = comment;
this.listener = listener;
}
@Override
protected Void doInBackground(Void... voids) {
try {
JSONArray commentJSONArray = new JSONObject(responseBody).getJSONArray(JSONUtils.DATA_KEY);
JSONObject commentFound = null;
for (int i = 0; i < commentJSONArray.length(); i++) {
JSONObject commentJSON = commentJSONArray.getJSONObject(i);
if (!commentJSON.isNull("id") && commentJSON.getString("id").equals(comment.getId())) {
commentFound = commentJSON;
break;
}
}
assert commentFound != null;
comment = parseRemovedComment(commentFound, comment);
} catch (JSONException e) {
e.printStackTrace();
comment = null;
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (comment != null)
listener.fetchSuccess(comment);
else
listener.fetchFailed();
}
}
}

View File

@ -1,51 +1,54 @@
package ml.docilealligator.infinityforreddit.comment;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import android.os.Handler;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.concurrent.Executor;
import ml.docilealligator.infinityforreddit.apis.RevedditAPI;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.JSONUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class FetchRemovedCommentReveddit {
public static void fetchRemovedComment(Retrofit retrofit, Comment comment, long postCreatedUtc, int nComments, FetchRemovedCommentListener listener) {
String parentIdWithoutPrefix = comment.getParentId().substring(3);
String rootCommentId = parentIdWithoutPrefix.equals(comment.getLinkId()) ? comment.getId() : parentIdWithoutPrefix;
retrofit.create(RevedditAPI.class).getRemovedComments(
APIUtils.getRevedditHeader(),
comment.getLinkId(),
(comment.getCommentTimeMillis() / 1000) - 1,
rootCommentId,
comment.getId(),
nComments,
postCreatedUtc / 1000,
true)
.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.isSuccessful()) {
new ParseCommentAsyncTask(response.body(), comment, listener).execute();
public static void fetchRemovedComment(Executor executor, Handler handler, Retrofit retrofit, Comment comment,
long postCreatedUtc, int nComments, FetchRemovedCommentListener listener) {
executor.execute(() -> {
String parentIdWithoutPrefix = comment.getParentId().substring(3);
String rootCommentId = parentIdWithoutPrefix.equals(comment.getLinkId()) ? comment.getId() : parentIdWithoutPrefix;
try {
Response<String> response = retrofit.create(RevedditAPI.class).getRemovedComments(
APIUtils.getRevedditHeader(),
comment.getLinkId(),
(comment.getCommentTimeMillis() / 1000) - 1,
rootCommentId,
comment.getId(),
nComments,
postCreatedUtc / 1000,
true).execute();
if (response.isSuccessful()) {
Comment removedComment = parseRemovedComment(new JSONObject(response.body()).getJSONObject(comment.getId()), comment);
handler.post(() -> {
if (removedComment != null) {
listener.fetchSuccess(removedComment);
} else {
listener.fetchFailed();
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
t.printStackTrace();
listener.fetchFailed();
}
});
});
} else {
handler.post(listener::fetchFailed);
}
} catch (IOException | JSONException e) {
e.printStackTrace();
handler.post(listener::fetchFailed);
}
});
}
private static Comment parseRemovedComment(JSONObject result, Comment comment) throws JSONException {
@ -53,10 +56,7 @@ public class FetchRemovedCommentReveddit {
String author = result.getString(JSONUtils.AUTHOR_KEY);
String body = Utils.modifyMarkdown(result.optString(JSONUtils.BODY_KEY).trim());
if (id.equals(comment.getId()) &&
(!author.equals(comment.getAuthor()) ||
!body.equals(comment.getCommentRawText()))
) {
if (id.equals(comment.getId()) && (!author.equals(comment.getAuthor()) || !body.equals(comment.getCommentRawText()))) {
comment.setAuthor(author);
comment.setCommentMarkdown(body);
comment.setCommentRawText(body);
@ -71,38 +71,4 @@ public class FetchRemovedCommentReveddit {
void fetchFailed();
}
private static class ParseCommentAsyncTask extends AsyncTask<Void, Void, Void> {
private final String responseBody;
private final FetchRemovedCommentListener listener;
Comment comment;
public ParseCommentAsyncTask(String responseBody, Comment comment, FetchRemovedCommentListener listener) {
this.responseBody = responseBody;
this.comment = comment;
this.listener = listener;
}
@Override
protected Void doInBackground(Void... voids) {
try {
JSONObject commentJSON = new JSONObject(responseBody).getJSONObject(comment.getId());
comment = parseRemovedComment(commentJSON, comment);
} catch (JSONException e) {
e.printStackTrace();
comment = null;
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (comment != null)
listener.fetchSuccess(comment);
else
listener.fetchFailed();
}
}
}

View File

@ -1722,8 +1722,7 @@ public class ViewPostDetailFragment extends Fragment implements FragmentCommunic
public void showRemovedComment(Comment comment, int position) {
Toast.makeText(activity, R.string.fetching_removed_comment, Toast.LENGTH_SHORT).show();
FetchRemovedComment.searchRemovedComment(
pushshiftRetrofit,
comment,
mExecutor, new Handler(), pushshiftRetrofit, comment,
new FetchRemovedComment.FetchRemovedCommentListener() {
@Override
public void fetchSuccess(Comment comment) {
@ -1733,17 +1732,19 @@ public class ViewPostDetailFragment extends Fragment implements FragmentCommunic
@Override
public void fetchFailed() {
// Reveddit fallback
FetchRemovedCommentReveddit.fetchRemovedComment(revedditRetrofit, comment, mPost.getPostTimeMillis(), mPost.getNComments(), new FetchRemovedCommentReveddit.FetchRemovedCommentListener() {
@Override
public void fetchSuccess(Comment comment) {
mCommentsAdapter.editComment(comment.getAuthor(), comment.getCommentMarkdown(), position);
}
FetchRemovedCommentReveddit.fetchRemovedComment(mExecutor, new Handler(), revedditRetrofit,
comment, mPost.getPostTimeMillis(), mPost.getNComments(),
new FetchRemovedCommentReveddit.FetchRemovedCommentListener() {
@Override
public void fetchSuccess(Comment comment) {
mCommentsAdapter.editComment(comment.getAuthor(), comment.getCommentMarkdown(), position);
}
@Override
public void fetchFailed() {
Toast.makeText(activity, R.string.show_removed_comment_failed, Toast.LENGTH_SHORT).show();
}
});
@Override
public void fetchFailed() {
Toast.makeText(activity, R.string.show_removed_comment_failed, Toast.LENGTH_SHORT).show();
}
});
}
});
}

View File

@ -204,7 +204,7 @@ public final class Utils {
}
String emote_url = s_key.getString(JSONUtils.U_KEY);
markdown = markdown.replace("![img](" + emote_id + ")", "[[" + emote_type + "]](" + emote_url + ") ");
markdown = markdown.replace("![img](" + emote_id + ")", "[" + emote_type + "](" + emote_url + ") ");
}
}
return markdown;