comments redo (logged-in endpoint)

This commit is contained in:
Austin Huang 2021-05-29 10:46:23 -04:00
parent 59750b1026
commit 890139a287
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
13 changed files with 590 additions and 363 deletions

View File

@ -17,7 +17,7 @@ public final class CommentsAdapter extends ListAdapter<Comment, CommentViewHolde
private static final DiffUtil.ItemCallback<Comment> DIFF_CALLBACK = new DiffUtil.ItemCallback<Comment>() {
@Override
public boolean areItemsTheSame(@NonNull final Comment oldItem, @NonNull final Comment newItem) {
return Objects.equals(oldItem.getId(), newItem.getId());
return Objects.equals(oldItem.getPk(), newItem.getPk());
}
@Override

View File

@ -123,7 +123,7 @@ public final class CommentViewHolder extends RecyclerView.ViewHolder {
private void setLikes(@NonNull final Comment comment, final boolean isReply) {
// final String likesString = itemView.getResources().getQuantityString(R.plurals.likes_count, likes, likes);
binding.likes.setText(String.valueOf(comment.getLikes()));
binding.likes.setText(String.valueOf(comment.getCommentLikeCount()));
binding.likes.setOnLongClickListener(v -> {
if (commentCallback == null) return false;
commentCallback.onViewLikes(comment);
@ -147,7 +147,7 @@ public final class CommentViewHolder extends RecyclerView.ViewHolder {
}
private void setReplies(@NonNull final Comment comment, final boolean isReply) {
final int replies = comment.getReplyCount();
final int replies = comment.getChildCommentCount();
binding.replies.setVisibility(View.VISIBLE);
final String text = isReply ? "" : String.valueOf(replies);
// final String string = itemView.getResources().getQuantityString(R.plurals.replies_count, replies, replies);

View File

@ -419,7 +419,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
final long locationId = locationModel.getPk();
// binding.swipeRefreshLayout.setRefreshing(true);
locationDetailsBinding.mainLocationImage.setImageURI("res:/" + R.drawable.ic_location);
// final String postCount = String.valueOf(locationModel.getCount());
// final String postCount = String.valueOf(locationModel.getChildCommentCount());
// final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline,
// locationModel.getPostCount() > 2000000000L
// ? 2000000000

View File

@ -126,7 +126,7 @@ public final class Helper {
if (navController == null) return;
try {
final Bundle bundle = new Bundle();
bundle.putString("postId", comment.getId());
bundle.putString("postId", comment.getPk());
bundle.putBoolean("isComment", true);
navController.navigate(R.id.action_global_likesViewerFragment, bundle);
} catch (Exception e) {

View File

@ -6,25 +6,24 @@ import java.io.Serializable
import java.util.*
class Comment(
val id: String,
val pk: String,
val text: String,
val timestamp: Long,
var likes: Long,
private var liked: Boolean,
val createdAt: Long,
var commentLikeCount: Long,
private var hasLikedComment: Boolean,
val user: User,
val replyCount: Int,
val isChild: Boolean,
val childCommentCount: Int
) : Serializable, Cloneable {
val dateTime: String
get() = TextUtils.epochSecondToString(timestamp)
get() = TextUtils.epochSecondToString(createdAt)
fun getLiked(): Boolean {
return liked
return hasLikedComment
}
fun setLiked(liked: Boolean) {
likes = if (liked) likes + 1 else likes - 1
this.liked = liked
commentLikeCount = if (hasLikedComment) commentLikeCount + 1 else commentLikeCount - 1
this.hasLikedComment = hasLikedComment
}
@Throws(CloneNotSupportedException::class)
@ -39,31 +38,29 @@ class Comment(
other as Comment
if (id != other.id) return false
if (pk != other.pk) return false
if (text != other.text) return false
if (timestamp != other.timestamp) return false
if (likes != other.likes) return false
if (liked != other.liked) return false
if (createdAt != other.createdAt) return false
if (commentLikeCount != other.commentLikeCount) return false
if (hasLikedComment != other.hasLikedComment) return false
if (user != other.user) return false
if (replyCount != other.replyCount) return false
if (isChild != other.isChild) return false
if (childCommentCount != other.childCommentCount) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
var result = pk.hashCode()
result = 31 * result + text.hashCode()
result = 31 * result + timestamp.hashCode()
result = 31 * result + likes.hashCode()
result = 31 * result + liked.hashCode()
result = 31 * result + createdAt.hashCode()
result = 31 * result + commentLikeCount.hashCode()
result = 31 * result + hasLikedComment.hashCode()
result = 31 * result + user.hashCode()
result = 31 * result + replyCount
result = 31 * result + isChild.hashCode()
result = 31 * result + childCommentCount
return result
}
override fun toString(): String {
return "Comment(id='$id', text='$text', timestamp=$timestamp, likes=$likes, liked=$liked, user=$user, replyCount=$replyCount, isChild=$isChild)"
return "Comment(pk='$pk', text='$text', createdAt=$createdAt, commentLikeCount=$commentLikeCount, hasLikedComment=$hasLikedComment, user=$user, childCommentCount=$childCommentCount)"
}
}

View File

@ -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);
}

View File

@ -28,26 +28,6 @@ public interface MediaRepository {
@Path("mediaId") final String mediaId,
@FieldMap final Map<String, String> signedForm);
@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);
@FormUrlEncoded
@POST("/api/v1/media/{mediaId}/edit_media/")
Call<String> editCaption(@Path("mediaId") final String mediaId,

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -25,14 +25,14 @@ import java.util.stream.IntStream;
import awais.instagrabber.R;
import awais.instagrabber.models.Comment;
import awais.instagrabber.models.Resource;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.GraphQLCommentsFetchResponse;
import awais.instagrabber.repositories.responses.ChildCommentsFetchResponse;
import awais.instagrabber.repositories.responses.CommentsFetchResponse;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.webservices.CommentService;
import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.MediaService;
import awais.instagrabber.webservices.ServiceCallback;
import retrofit2.Call;
import retrofit2.Callback;
@ -48,7 +48,7 @@ public class CommentsViewerViewModel extends ViewModel {
private final MutableLiveData<Resource<List<Comment>>> rootList = new MutableLiveData<>();
private final MutableLiveData<Integer> rootCount = new MutableLiveData<>(0);
private final MutableLiveData<Resource<List<Comment>>> replyList = new MutableLiveData<>();
private final GraphQLService service;
private final GraphQLService graphQLService;
private String shortCode;
private String postId;
@ -57,18 +57,68 @@ public class CommentsViewerViewModel extends ViewModel {
private Comment repliesParent;
private String repliesCursor;
private boolean repliesHasNext = true;
private final MediaService mediaService;
private final CommentService commentService;
private List<Comment> prevReplies;
private String prevRepliesCursor;
private boolean prevRepliesHasNext = true;
private final ServiceCallback<CommentsFetchResponse> ccb = new ServiceCallback<CommentsFetchResponse>() {
@Override
public void onSuccess(final CommentsFetchResponse result) {
// Log.d(TAG, "onSuccess: " + result);
List<Comment> comments = result.getComments();
if (rootCursor == null) {
rootCount.postValue(result.getCommentCount());
}
if (rootCursor != null) {
comments = mergeList(rootList, comments);
}
rootCursor = result.getNextMinId();
rootHasNext = result.hasNext();
rootList.postValue(Resource.success(comments));
}
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "onFailure: ", t);
rootList.postValue(Resource.error(t.getMessage(), getPrevList(rootList)));
}
};
private final ServiceCallback<ChildCommentsFetchResponse> rcb = new ServiceCallback<ChildCommentsFetchResponse>() {
@Override
public void onSuccess(final ChildCommentsFetchResponse result) {
// Log.d(TAG, "onSuccess: " + result);
List<Comment> comments = result.getChildComments();
// Replies
if (repliesCursor == null) {
// add parent to top of replies
comments = ImmutableList.<Comment>builder()
.add(repliesParent)
.addAll(comments)
.build();
}
if (repliesCursor != null) {
comments = mergeList(replyList, comments);
}
repliesCursor = result.getNextMinId();
repliesHasNext = result.hasNext();
replyList.postValue(Resource.success(comments));
}
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "onFailure: ", t);
replyList.postValue(Resource.error(t.getMessage(), getPrevList(replyList)));
}
};
public CommentsViewerViewModel() {
service = GraphQLService.getInstance();
graphQLService = GraphQLService.getInstance();
final String cookie = settingsHelper.getString(Constants.COOKIE);
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userIdFromCookie);
commentService = CommentService.getInstance(deviceUuid, csrfToken, userIdFromCookie);
}
public void setCurrentUser(final User currentUser) {
@ -108,87 +158,45 @@ public class CommentsViewerViewModel extends ViewModel {
}
public void fetchComments() {
if (shortCode == null) return;
fetchComments(shortCode, true);
if (shortCode == null || postId == null) return;
if (!rootHasNext) return;
rootList.postValue(Resource.loading(getPrevList(rootList)));
if (isLoggedIn.getValue()) {
commentService.fetchComments(postId, rootCursor, ccb);
return;
}
final Call<String> request = graphQLService.fetchComments(shortCode, true, rootCursor);
enqueueRequest(request, true, shortCode, ccb);
}
public void fetchReplies() {
if (repliesParent == null) return;
fetchReplies(repliesParent.getId());
fetchReplies(repliesParent.getPk());
}
public void fetchReplies(@NonNull final String commentId) {
fetchComments(commentId, false);
}
public void fetchComments(@NonNull final String shortCodeOrCommentId,
final boolean root) {
if (root) {
if (!rootHasNext) return;
rootList.postValue(Resource.loading(getPrevList(rootList)));
if (!repliesHasNext) return;
final List<Comment> list;
if (repliesParent != null && !Objects.equals(repliesParent.getPk(), commentId)) {
repliesCursor = null;
repliesHasNext = false;
list = Collections.emptyList();
} else {
if (!repliesHasNext) return;
final List<Comment> list;
if (repliesParent != null && !Objects.equals(repliesParent.getId(), shortCodeOrCommentId)) {
repliesCursor = null;
repliesHasNext = false;
list = Collections.emptyList();
} else {
list = getPrevList(replyList);
}
replyList.postValue(Resource.loading(list));
list = getPrevList(replyList);
}
final Call<String> request = service.fetchComments(shortCodeOrCommentId, root, root ? rootCursor : repliesCursor);
enqueueRequest(request, root, shortCodeOrCommentId, new ServiceCallback<GraphQLCommentsFetchResponse>() {
@Override
public void onSuccess(final GraphQLCommentsFetchResponse result) {
// Log.d(TAG, "onSuccess: " + result);
List<Comment> comments = result.getComments();
if (root) {
if (rootCursor == null) {
rootCount.postValue(result.getCount());
}
if (rootCursor != null) {
comments = mergeList(rootList, comments);
}
rootCursor = result.getCursor();
rootHasNext = result.hasNext();
rootList.postValue(Resource.success(comments));
return;
}
// Replies
if (repliesCursor == null) {
// add parent to top of replies
comments = ImmutableList.<Comment>builder()
.add(repliesParent)
.addAll(comments)
.build();
}
if (repliesCursor != null) {
comments = mergeList(replyList, comments);
}
repliesCursor = result.getCursor();
repliesHasNext = result.hasNext();
replyList.postValue(Resource.success(comments));
}
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "onFailure: ", t);
if (root) {
rootList.postValue(Resource.error(t.getMessage(), getPrevList(rootList)));
return;
}
replyList.postValue(Resource.error(t.getMessage(), getPrevList(replyList)));
}
});
replyList.postValue(Resource.loading(list));
if (isLoggedIn.getValue()) {
commentService.fetchChildComments(postId, commentId, rootCursor, rcb);
return;
}
final Call<String> request = graphQLService.fetchComments(commentId, false, repliesCursor);
enqueueRequest(request, false, commentId, rcb);
}
private void enqueueRequest(@NonNull final Call<String> request,
final boolean root,
final String shortCodeOrCommentId,
final ServiceCallback<GraphQLCommentsFetchResponse> callback) {
final ServiceCallback callback) {
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
@ -208,14 +216,16 @@ public class CommentsViewerViewModel extends ViewModel {
final int count = body.optInt("count");
final JSONObject pageInfo = body.getJSONObject("page_info");
final boolean hasNextPage = pageInfo.getBoolean("has_next_page");
final String endCursor = pageInfo.isNull("end_cursor") ? null : pageInfo.optString("end_cursor");
final String endCursor = pageInfo.isNull("end_cursor") || !hasNextPage ? null : pageInfo.optString("end_cursor");
final JSONArray commentsJsonArray = body.getJSONArray("edges");
final ImmutableList.Builder<Comment> builder = ImmutableList.builder();
for (int i = 0; i < commentsJsonArray.length(); i++) {
final Comment commentModel = getComment(commentsJsonArray.getJSONObject(i).getJSONObject("node"), root);
builder.add(commentModel);
}
callback.onSuccess(new GraphQLCommentsFetchResponse(count, endCursor, hasNextPage, builder.build()));
callback.onSuccess(root ?
new CommentsFetchResponse(count, endCursor, builder.build()) :
new ChildCommentsFetchResponse(count, endCursor, builder.build()));
} catch (Exception e) {
Log.e(TAG, "onResponse", e);
callback.onFailure(e);
@ -252,8 +262,7 @@ public class CommentsViewerViewModel extends ViewModel {
likedBy != null ? likedBy.optLong("count", 0) : 0,
commentJsonObject.getBoolean("viewer_has_liked"),
user,
replyCount,
!root);
replyCount);
}
@NonNull
@ -278,12 +287,12 @@ public class CommentsViewerViewModel extends ViewModel {
public void showReplies(final Comment comment) {
if (comment == null) return;
if (repliesParent == null || !Objects.equals(repliesParent.getId(), comment.getId())) {
if (repliesParent == null || !Objects.equals(repliesParent.getPk(), comment.getPk())) {
repliesParent = comment;
prevReplies = null;
prevRepliesCursor = null;
prevRepliesHasNext = true;
fetchReplies(comment.getId());
fetchReplies(comment.getPk());
return;
}
if (prevReplies != null && !prevReplies.isEmpty()) {
@ -296,7 +305,7 @@ public class CommentsViewerViewModel extends ViewModel {
// prev list was null or empty, fetch
prevRepliesCursor = null;
prevRepliesHasNext = true;
fetchReplies(comment.getId());
fetchReplies(comment.getPk());
}
public LiveData<Resource<Object>> likeComment(@NonNull final Comment comment, final boolean liked, final boolean isReply) {
@ -319,9 +328,9 @@ public class CommentsViewerViewModel extends ViewModel {
}
};
if (liked) {
mediaService.commentLike(comment.getId(), callback);
commentService.commentLike(comment.getPk(), callback);
} else {
mediaService.commentUnlike(comment.getId(), callback);
commentService.commentUnlike(comment.getPk(), callback);
}
return data;
}
@ -333,7 +342,7 @@ public class CommentsViewerViewModel extends ViewModel {
if (list == null) return;
final List<Comment> copy = new ArrayList<>(list);
OptionalInt indexOpt = IntStream.range(0, copy.size())
.filter(i -> copy.get(i) != null && Objects.equals(copy.get(i).getId(), comment.getId()))
.filter(i -> copy.get(i) != null && Objects.equals(copy.get(i).getPk(), comment.getPk()))
.findFirst();
if (!indexOpt.isPresent()) return;
try {
@ -352,13 +361,13 @@ public class CommentsViewerViewModel extends ViewModel {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(Resource.loading(null));
String replyToId = null;
if (isReply && repliesParent != null) {
replyToId = repliesParent.getId();
replyToId = repliesParent.getPk();
}
if (isReply && replyToId == null) {
data.postValue(Resource.error(null, null));
return data;
}
mediaService.comment(postId, text, replyToId, new ServiceCallback<Comment>() {
commentService.comment(postId, text, replyToId, new ServiceCallback<Comment>() {
@Override
public void onSuccess(final Comment result) {
if (result == null) {
@ -396,12 +405,12 @@ public class CommentsViewerViewModel extends ViewModel {
public void translate(@NonNull final Comment comment,
@NonNull final ServiceCallback<String> callback) {
mediaService.translate(comment.getId(), "2", callback);
commentService.translate(comment.getPk(), callback);
}
public LiveData<Resource<Object>> deleteComment(@NonNull final Comment comment, final boolean isReply) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(Resource.loading(null));
mediaService.deleteComment(postId, comment.getId(), new ServiceCallback<Boolean>() {
commentService.deleteComment(postId, comment.getPk(), new ServiceCallback<Boolean>() {
@Override
public void onSuccess(final Boolean result) {
if (result == null || !result) {
@ -425,7 +434,7 @@ public class CommentsViewerViewModel extends ViewModel {
final List<Comment> list = getPrevList(isReply ? replyList : rootList);
final List<Comment> updated = list.stream()
.filter(Objects::nonNull)
.filter(c -> !Objects.equals(c.getId(), comment.getId()))
.filter(c -> !Objects.equals(c.getPk(), comment.getPk()))
.collect(Collectors.toList());
final MutableLiveData<Resource<List<Comment>>> liveData = isReply ? replyList : rootList;
liveData.postValue(Resource.success(updated));

View File

@ -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);
}
});
}
}

View File

@ -171,181 +171,6 @@ public class MediaService extends BaseService {
});
}
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"),
0,
false,
user,
0,
!TextUtils.isEmpty(replyToCommentId)
);
}
}
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 editCaption(final String postId,
final String newCaption,
@NonNull final ServiceCallback<Boolean> callback) {