Austin Huang
4 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
13 changed files with 590 additions and 363 deletions
-
2app/src/main/java/awais/instagrabber/adapters/CommentsAdapter.java
-
4app/src/main/java/awais/instagrabber/adapters/viewholder/CommentViewHolder.java
-
2app/src/main/java/awais/instagrabber/fragments/LocationFragment.java
-
2app/src/main/java/awais/instagrabber/fragments/comments/Helper.java
-
43app/src/main/java/awais/instagrabber/models/Comment.kt
-
49app/src/main/java/awais/instagrabber/repositories/CommentRepository.java
-
20app/src/main/java/awais/instagrabber/repositories/MediaRepository.java
-
47app/src/main/java/awais/instagrabber/repositories/responses/ChildCommentsFetchResponse.java
-
47app/src/main/java/awais/instagrabber/repositories/responses/CommentsFetchResponse.java
-
51app/src/main/java/awais/instagrabber/repositories/responses/GraphQLCommentsFetchResponse.java
-
169app/src/main/java/awais/instagrabber/viewmodels/CommentsViewerViewModel.java
-
324app/src/main/java/awais/instagrabber/webservices/CommentService.java
-
175app/src/main/java/awais/instagrabber/webservices/MediaService.java
@ -0,0 +1,49 @@ |
|||||
|
package awais.instagrabber.repositories; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
import awais.instagrabber.repositories.responses.CommentsFetchResponse; |
||||
|
import awais.instagrabber.repositories.responses.ChildCommentsFetchResponse; |
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.http.FieldMap; |
||||
|
import retrofit2.http.FormUrlEncoded; |
||||
|
import retrofit2.http.GET; |
||||
|
import retrofit2.http.Header; |
||||
|
import retrofit2.http.POST; |
||||
|
import retrofit2.http.Path; |
||||
|
import retrofit2.http.Query; |
||||
|
import retrofit2.http.QueryMap; |
||||
|
|
||||
|
public interface CommentRepository { |
||||
|
@GET("/api/v1/media/{mediaId}/comments/") |
||||
|
Call<CommentsFetchResponse> fetchComments(@Path("mediaId") final String mediaId, |
||||
|
@QueryMap final Map<String, String> queryMap); |
||||
|
|
||||
|
@GET("/api/v1/media/{mediaId}/comments/{commentId}/inline_child_comments/") |
||||
|
Call<ChildCommentsFetchResponse> fetchChildComments(@Path("mediaId") final String mediaId, |
||||
|
@Path("commentId") final String commentId, |
||||
|
@QueryMap final Map<String, String> queryMap); |
||||
|
|
||||
|
@FormUrlEncoded |
||||
|
@POST("/api/v1/media/{mediaId}/comment/") |
||||
|
Call<String> comment(@Path("mediaId") final String mediaId, |
||||
|
@FieldMap final Map<String, String> signedForm); |
||||
|
|
||||
|
@FormUrlEncoded |
||||
|
@POST("/api/v1/media/{mediaId}/comment/bulk_delete/") |
||||
|
Call<String> commentsBulkDelete(@Path("mediaId") final String mediaId, |
||||
|
@FieldMap final Map<String, String> signedForm); |
||||
|
|
||||
|
@FormUrlEncoded |
||||
|
@POST("/api/v1/media/{commentId}/comment_like/") |
||||
|
Call<String> commentLike(@Path("commentId") final String commentId, |
||||
|
@FieldMap final Map<String, String> signedForm); |
||||
|
|
||||
|
@FormUrlEncoded |
||||
|
@POST("/api/v1/media/{commentId}/comment_unlike/") |
||||
|
Call<String> commentUnlike(@Path("commentId") final String commentId, |
||||
|
@FieldMap final Map<String, String> signedForm); |
||||
|
|
||||
|
@GET("/api/v1/language/translate/") |
||||
|
Call<String> translate(@QueryMap final Map<String, String> form); |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
package awais.instagrabber.repositories.responses; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import awais.instagrabber.models.Comment; |
||||
|
|
||||
|
public class ChildCommentsFetchResponse { |
||||
|
private final int childCommentCount; |
||||
|
private final String nextMinId; |
||||
|
private final List<Comment> childComments; |
||||
|
|
||||
|
public ChildCommentsFetchResponse(final int childCommentCount, |
||||
|
final String nextMinId, // unconfirmed |
||||
|
final List<Comment> childComments) { |
||||
|
this.childCommentCount = childCommentCount; |
||||
|
this.nextMinId = nextMinId; |
||||
|
this.childComments = childComments; |
||||
|
} |
||||
|
|
||||
|
public int getChildCommentCount() { |
||||
|
return childCommentCount; |
||||
|
} |
||||
|
|
||||
|
public String getNextMinId() { |
||||
|
return nextMinId; |
||||
|
} |
||||
|
|
||||
|
public boolean hasNext() { |
||||
|
return nextMinId != null; |
||||
|
} |
||||
|
|
||||
|
public List<Comment> getChildComments() { |
||||
|
return childComments; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "CommentsFetchResponse{" + |
||||
|
"childCommentCount=" + childCommentCount + |
||||
|
", nextMinId='" + nextMinId + '\'' + |
||||
|
", childComments=" + childComments + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
package awais.instagrabber.repositories.responses; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import awais.instagrabber.models.Comment; |
||||
|
|
||||
|
public class CommentsFetchResponse { |
||||
|
private final int commentCount; |
||||
|
private final String nextMinId; |
||||
|
private final List<Comment> comments; |
||||
|
|
||||
|
public CommentsFetchResponse(final int commentCount, |
||||
|
final String nextMinId, |
||||
|
final List<Comment> comments) { |
||||
|
this.commentCount = commentCount; |
||||
|
this.nextMinId = nextMinId; |
||||
|
this.comments = comments; |
||||
|
} |
||||
|
|
||||
|
public int getCommentCount() { |
||||
|
return commentCount; |
||||
|
} |
||||
|
|
||||
|
public String getNextMinId() { |
||||
|
return nextMinId; |
||||
|
} |
||||
|
|
||||
|
public boolean hasNext() { |
||||
|
return nextMinId != null; |
||||
|
} |
||||
|
|
||||
|
public List<Comment> getComments() { |
||||
|
return comments; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "CommentsFetchResponse{" + |
||||
|
"commentCount=" + commentCount + |
||||
|
", nextMinId='" + nextMinId + '\'' + |
||||
|
", comments=" + comments + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
@ -1,51 +0,0 @@ |
|||||
package awais.instagrabber.repositories.responses; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.util.List; |
|
||||
|
|
||||
import awais.instagrabber.models.Comment; |
|
||||
|
|
||||
public class GraphQLCommentsFetchResponse { |
|
||||
private final int count; |
|
||||
private final String cursor; |
|
||||
private final boolean hasNext; |
|
||||
private final List<Comment> comments; |
|
||||
|
|
||||
public GraphQLCommentsFetchResponse(final int count, |
|
||||
final String cursor, |
|
||||
final boolean hasNext, |
|
||||
final List<Comment> comments) { |
|
||||
this.count = count; |
|
||||
this.cursor = cursor; |
|
||||
this.hasNext = hasNext; |
|
||||
this.comments = comments; |
|
||||
} |
|
||||
|
|
||||
public int getCount() { |
|
||||
return count; |
|
||||
} |
|
||||
|
|
||||
public String getCursor() { |
|
||||
return cursor; |
|
||||
} |
|
||||
|
|
||||
public boolean hasNext() { |
|
||||
return hasNext; |
|
||||
} |
|
||||
|
|
||||
public List<Comment> getComments() { |
|
||||
return comments; |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
@Override |
|
||||
public String toString() { |
|
||||
return "GraphQLCommentsFetchResponse{" + |
|
||||
"count=" + count + |
|
||||
", cursor='" + cursor + '\'' + |
|
||||
", hasNext=" + hasNext + |
|
||||
", comments=" + comments + |
|
||||
'}'; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,324 @@ |
|||||
|
package awais.instagrabber.webservices; |
||||
|
|
||||
|
import android.util.Log; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import com.google.gson.Gson; |
||||
|
|
||||
|
import org.json.JSONException; |
||||
|
import org.json.JSONObject; |
||||
|
|
||||
|
import java.util.Collections; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Objects; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
import awais.instagrabber.models.Comment; |
||||
|
import awais.instagrabber.repositories.CommentRepository; |
||||
|
import awais.instagrabber.repositories.responses.ChildCommentsFetchResponse; |
||||
|
import awais.instagrabber.repositories.responses.CommentsFetchResponse; |
||||
|
import awais.instagrabber.repositories.responses.User; |
||||
|
import awais.instagrabber.utils.TextUtils; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.Callback; |
||||
|
import retrofit2.Response; |
||||
|
|
||||
|
public class CommentService extends BaseService { |
||||
|
private static final String TAG = "CommentService"; |
||||
|
|
||||
|
private final CommentRepository repository; |
||||
|
private final String deviceUuid, csrfToken; |
||||
|
private final long userId; |
||||
|
|
||||
|
private static CommentService instance; |
||||
|
|
||||
|
private CommentService(final String deviceUuid, |
||||
|
final String csrfToken, |
||||
|
final long userId) { |
||||
|
this.deviceUuid = deviceUuid; |
||||
|
this.csrfToken = csrfToken; |
||||
|
this.userId = userId; |
||||
|
repository = RetrofitFactory.INSTANCE |
||||
|
.getRetrofit() |
||||
|
.create(CommentRepository.class); |
||||
|
} |
||||
|
|
||||
|
public String getCsrfToken() { |
||||
|
return csrfToken; |
||||
|
} |
||||
|
|
||||
|
public String getDeviceUuid() { |
||||
|
return deviceUuid; |
||||
|
} |
||||
|
|
||||
|
public long getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public static CommentService getInstance(final String deviceUuid, final String csrfToken, final long userId) { |
||||
|
if (instance == null |
||||
|
|| !Objects.equals(instance.getCsrfToken(), csrfToken) |
||||
|
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid) |
||||
|
|| !Objects.equals(instance.getUserId(), userId)) { |
||||
|
instance = new CommentService(deviceUuid, csrfToken, userId); |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
public void fetchComments(@NonNull final String mediaId, |
||||
|
final String maxId, |
||||
|
@NonNull final ServiceCallback<CommentsFetchResponse> callback) { |
||||
|
final Map<String, String> form = new HashMap<>(); |
||||
|
form.put("can_support_threading", "true"); |
||||
|
if (maxId != null) form.put("max_id", maxId); |
||||
|
final Call<CommentsFetchResponse> request = repository.fetchComments(mediaId, form); |
||||
|
request.enqueue(new Callback<CommentsFetchResponse>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<CommentsFetchResponse> call, @NonNull final Response<CommentsFetchResponse> response) { |
||||
|
if (callback == null) return; |
||||
|
final CommentsFetchResponse cfr = response.body(); |
||||
|
if (cfr == null) callback.onFailure(new Exception("response is empty")); |
||||
|
callback.onSuccess(cfr); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<CommentsFetchResponse> call, @NonNull final Throwable t) { |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void fetchChildComments(@NonNull final String mediaId, |
||||
|
@NonNull final String commentId, |
||||
|
final String maxId, |
||||
|
@NonNull final ServiceCallback<ChildCommentsFetchResponse> callback) { |
||||
|
final Map<String, String> form = new HashMap<>(); |
||||
|
if (maxId != null) form.put("max_id", maxId); |
||||
|
final Call<ChildCommentsFetchResponse> request = repository.fetchChildComments(mediaId, commentId, form); |
||||
|
request.enqueue(new Callback<ChildCommentsFetchResponse>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<ChildCommentsFetchResponse> call, @NonNull final Response<ChildCommentsFetchResponse> response) { |
||||
|
if (callback == null) return; |
||||
|
final ChildCommentsFetchResponse cfr = response.body(); |
||||
|
if (cfr == null) callback.onFailure(new Exception("response is empty")); |
||||
|
callback.onSuccess(cfr); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<ChildCommentsFetchResponse> call, @NonNull final Throwable t) { |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void comment(@NonNull final String mediaId, |
||||
|
@NonNull final String comment, |
||||
|
final String replyToCommentId, |
||||
|
@NonNull final ServiceCallback<Comment> callback) { |
||||
|
final String module = "self_comments_v2"; |
||||
|
final Map<String, Object> form = new HashMap<>(); |
||||
|
// form.put("user_breadcrumb", userBreadcrumb(comment.length())); |
||||
|
form.put("idempotence_token", UUID.randomUUID().toString()); |
||||
|
form.put("_csrftoken", csrfToken); |
||||
|
form.put("_uid", userId); |
||||
|
form.put("_uuid", deviceUuid); |
||||
|
form.put("comment_text", comment); |
||||
|
form.put("containermodule", module); |
||||
|
if (!TextUtils.isEmpty(replyToCommentId)) { |
||||
|
form.put("replied_to_comment_id", replyToCommentId); |
||||
|
} |
||||
|
final Map<String, String> signedForm = Utils.sign(form); |
||||
|
final Call<String> commentRequest = repository.comment(mediaId, signedForm); |
||||
|
commentRequest.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) { |
||||
|
Log.e(TAG, "Error occurred while creating comment"); |
||||
|
callback.onSuccess(null); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
// final String status = jsonObject.optString("status"); |
||||
|
final JSONObject commentJsonObject = jsonObject.optJSONObject("comment"); |
||||
|
Comment comment = null; |
||||
|
if (commentJsonObject != null) { |
||||
|
final JSONObject userJsonObject = commentJsonObject.optJSONObject("user"); |
||||
|
if (userJsonObject != null) { |
||||
|
final Gson gson = new Gson(); |
||||
|
final User user = gson.fromJson(userJsonObject.toString(), User.class); |
||||
|
comment = new Comment( |
||||
|
commentJsonObject.optString("pk"), |
||||
|
commentJsonObject.optString("text"), |
||||
|
commentJsonObject.optLong("created_at"), |
||||
|
0L, |
||||
|
false, |
||||
|
user, |
||||
|
0 |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
callback.onSuccess(comment); |
||||
|
} catch (Exception e) { |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void deleteComment(final String mediaId, |
||||
|
final String commentId, |
||||
|
@NonNull final ServiceCallback<Boolean> callback) { |
||||
|
deleteComments(mediaId, Collections.singletonList(commentId), callback); |
||||
|
} |
||||
|
|
||||
|
public void deleteComments(final String mediaId, |
||||
|
final List<String> commentIds, |
||||
|
@NonNull final ServiceCallback<Boolean> callback) { |
||||
|
final Map<String, Object> form = new HashMap<>(); |
||||
|
form.put("comment_ids_to_delete", android.text.TextUtils.join(",", commentIds)); |
||||
|
form.put("_csrftoken", csrfToken); |
||||
|
form.put("_uid", userId); |
||||
|
form.put("_uuid", deviceUuid); |
||||
|
final Map<String, String> signedForm = Utils.sign(form); |
||||
|
final Call<String> bulkDeleteRequest = repository.commentsBulkDelete(mediaId, signedForm); |
||||
|
bulkDeleteRequest.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) { |
||||
|
Log.e(TAG, "Error occurred while deleting comments"); |
||||
|
callback.onSuccess(false); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
final String status = jsonObject.optString("status"); |
||||
|
callback.onSuccess(status.equals("ok")); |
||||
|
} catch (JSONException e) { |
||||
|
// Log.e(TAG, "Error parsing body", e); |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
// Log.e(TAG, "Error deleting comments", t); |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void commentLike(@NonNull final String commentId, |
||||
|
@NonNull final ServiceCallback<Boolean> callback) { |
||||
|
final Map<String, Object> form = new HashMap<>(); |
||||
|
form.put("_csrftoken", csrfToken); |
||||
|
// form.put("_uid", userId); |
||||
|
// form.put("_uuid", deviceUuid); |
||||
|
final Map<String, String> signedForm = Utils.sign(form); |
||||
|
final Call<String> commentLikeRequest = repository.commentLike(commentId, signedForm); |
||||
|
commentLikeRequest.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) { |
||||
|
Log.e(TAG, "Error occurred while liking comment"); |
||||
|
callback.onSuccess(false); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
final String status = jsonObject.optString("status"); |
||||
|
callback.onSuccess(status.equals("ok")); |
||||
|
} catch (JSONException e) { |
||||
|
// Log.e(TAG, "Error parsing body", e); |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
Log.e(TAG, "Error liking comment", t); |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void commentUnlike(final String commentId, |
||||
|
@NonNull final ServiceCallback<Boolean> callback) { |
||||
|
final Map<String, Object> form = new HashMap<>(); |
||||
|
form.put("_csrftoken", csrfToken); |
||||
|
// form.put("_uid", userId); |
||||
|
// form.put("_uuid", deviceUuid); |
||||
|
final Map<String, String> signedForm = Utils.sign(form); |
||||
|
final Call<String> commentUnlikeRequest = repository.commentUnlike(commentId, signedForm); |
||||
|
commentUnlikeRequest.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) { |
||||
|
Log.e(TAG, "Error occurred while unliking comment"); |
||||
|
callback.onSuccess(false); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
final String status = jsonObject.optString("status"); |
||||
|
callback.onSuccess(status.equals("ok")); |
||||
|
} catch (JSONException e) { |
||||
|
// Log.e(TAG, "Error parsing body", e); |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
Log.e(TAG, "Error unliking comment", t); |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void translate(final String id, |
||||
|
@NonNull final ServiceCallback<String> callback) { |
||||
|
final Map<String, String> form = new HashMap<>(); |
||||
|
form.put("id", String.valueOf(id)); |
||||
|
form.put("type", "2"); |
||||
|
final Call<String> request = repository.translate(form); |
||||
|
request.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) { |
||||
|
Log.e(TAG, "Error occurred while translating"); |
||||
|
callback.onSuccess(null); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
final String translation = jsonObject.optString("translation"); |
||||
|
callback.onSuccess(translation); |
||||
|
} catch (JSONException e) { |
||||
|
// Log.e(TAG, "Error parsing body", e); |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
Log.e(TAG, "Error translating", t); |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue