1
0
Fork 0
mirror of https://github.com/KokaKiwi/BarInsta synced 2026-03-05 12:01:35 +00:00

Merge branch 'master' into dm-notifications-enhancements

This commit is contained in:
Austin Huang 2021-03-05 14:21:24 -05:00 committed by GitHub
commit d6539bddc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1000 additions and 792 deletions

View file

@ -11,24 +11,25 @@ import androidx.recyclerview.widget.ListAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
import awais.instagrabber.databinding.ItemNotificationBinding;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.responses.Notification;
public final class NotificationsAdapter extends ListAdapter<NotificationModel, NotificationViewHolder> {
public final class NotificationsAdapter extends ListAdapter<Notification, NotificationViewHolder> {
private final OnNotificationClickListener notificationClickListener;
private static final DiffUtil.ItemCallback<NotificationModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<NotificationModel>() {
private static final DiffUtil.ItemCallback<Notification> DIFF_CALLBACK = new DiffUtil.ItemCallback<Notification>() {
@Override
public boolean areItemsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
return oldItem.getId().equals(newItem.getId());
public boolean areItemsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
return oldItem.getPk().equals(newItem.getPk());
}
@Override
public boolean areContentsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
return oldItem.getId().equals(newItem.getId());
public boolean areContentsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
return oldItem.getPk().equals(newItem.getPk());
}
};
@ -47,12 +48,12 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
@Override
public void onBindViewHolder(@NonNull final NotificationViewHolder holder, final int position) {
final NotificationModel notificationModel = getItem(position);
holder.bind(notificationModel, notificationClickListener);
final Notification Notification = getItem(position);
holder.bind(Notification, notificationClickListener);
}
@Override
public void submitList(@Nullable final List<NotificationModel> list, @Nullable final Runnable commitCallback) {
public void submitList(@Nullable final List<Notification> list, @Nullable final Runnable commitCallback) {
if (list == null) {
super.submitList(null, commitCallback);
return;
@ -61,7 +62,7 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
}
@Override
public void submitList(@Nullable final List<NotificationModel> list) {
public void submitList(@Nullable final List<Notification> list) {
if (list == null) {
super.submitList(null);
return;
@ -69,8 +70,10 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
super.submitList(sort(list));
}
private List<NotificationModel> sort(final List<NotificationModel> list) {
final List<NotificationModel> listCopy = new ArrayList<>(list);
private List<Notification> sort(final List<Notification> list) {
final List<Notification> listCopy = new ArrayList<>(list).stream()
.filter(i -> i.getType() != null)
.collect(Collectors.toList());
Collections.sort(listCopy, (o1, o2) -> {
// keep requests at top
if (o1.getType() == o2.getType()
@ -79,16 +82,16 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
else if (o1.getType() == NotificationType.REQUEST) return -1;
else if (o2.getType() == NotificationType.REQUEST) return 1;
// timestamp
return Long.compare(o2.getTimestamp(), o1.getTimestamp());
return Double.compare(o2.getArgs().getTimestamp(), o1.getArgs().getTimestamp());
});
return listCopy;
}
public interface OnNotificationClickListener {
void onNotificationClick(final NotificationModel model);
void onNotificationClick(final Notification model);
void onProfileClick(final String username);
void onPreviewClick(final NotificationModel model);
void onPreviewClick(final Notification model);
}
}

View file

@ -8,8 +8,9 @@ import androidx.recyclerview.widget.RecyclerView;
import awais.instagrabber.R;
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
import awais.instagrabber.databinding.ItemNotificationBinding;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.responses.Notification;
import awais.instagrabber.repositories.responses.NotificationArgs;
public final class NotificationViewHolder extends RecyclerView.ViewHolder {
private final ItemNotificationBinding binding;
@ -19,22 +20,23 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
this.binding = binding;
}
public void bind(final NotificationModel model,
public void bind(final Notification model,
final OnNotificationClickListener notificationClickListener) {
if (model == null) return;
int text = -1;
CharSequence subtext = null;
final NotificationArgs args = model.getArgs();
switch (model.getType()) {
case LIKE:
text = R.string.liked_notif;
break;
case COMMENT:
text = R.string.comment_notif;
subtext = model.getText();
subtext = args.getText();
break;
case COMMENT_MENTION:
text = R.string.mention_notif;
subtext = model.getText();
subtext = args.getText();
break;
case TAGGED:
text = R.string.tagged_notif;
@ -44,45 +46,50 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
break;
case REQUEST:
text = R.string.request_notif;
subtext = model.getText();
subtext = args.getText();
break;
case COMMENT_LIKE:
case TAGGED_COMMENT:
case RESPONDED_STORY:
subtext = model.getText();
subtext = args.getText();
break;
case AYML:
subtext = model.getPreviewPic();
subtext = args.getFullName();
break;
}
binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? model.getText() : subtext);
binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? args.getText() : subtext);
if (text == -1 && subtext != null) {
binding.tvComment.setText(subtext);
binding.tvComment.setVisibility(TextUtils.isEmpty(subtext) ? View.GONE : View.VISIBLE);
binding.tvComment.setText(args.getText());
binding.tvComment.setVisibility(TextUtils.isEmpty(args.getText()) || args.getText().equals(args.getFullName())
? View.GONE : View.VISIBLE);
binding.tvSubComment.setText(subtext);
binding.tvSubComment.setVisibility(model.getType() == NotificationType.AYML ? View.VISIBLE : View.GONE);
} else if (text != -1) {
binding.tvComment.setText(text);
binding.tvSubComment.setVisibility(subtext == null ? View.GONE : View.VISIBLE);
}
binding.tvDate.setVisibility(model.getType() == NotificationType.AYML ? View.GONE : View.VISIBLE);
if (model.getType() != NotificationType.REQUEST && model.getType() != NotificationType.AYML) {
binding.tvDate.setText(model.getDateTime());
binding.tvDate.setText(args.getDateTime());
}
binding.tvUsername.setText(model.getUsername());
binding.ivProfilePic.setImageURI(model.getProfilePic());
binding.isVerified.setVisibility(args.isVerified() ? View.VISIBLE : View.GONE);
binding.tvUsername.setText(args.getUsername());
binding.ivProfilePic.setImageURI(args.getProfilePic());
binding.ivProfilePic.setOnClickListener(v -> {
if (notificationClickListener == null) return;
notificationClickListener.onProfileClick(model.getUsername());
notificationClickListener.onProfileClick(args.getUsername());
});
if (model.getType() == NotificationType.AYML) {
binding.ivPreviewPic.setVisibility(View.GONE);
} else if (TextUtils.isEmpty(model.getPreviewPic())) {
} else if (args.getMedia() == null) {
binding.ivPreviewPic.setVisibility(View.INVISIBLE);
} else {
binding.ivPreviewPic.setVisibility(View.VISIBLE);
binding.ivPreviewPic.setImageURI(model.getPreviewPic());
binding.ivPreviewPic.setImageURI(args.getMedia().get(0).getImage());
binding.ivPreviewPic.setOnClickListener(v -> {
if (notificationClickListener == null) return;
notificationClickListener.onPreviewClick(model);

View file

@ -366,7 +366,7 @@ public final class DirectInboxItemViewHolder extends RecyclerView.ViewHolder {
}
}
binding.unread.setVisibility(read ? View.GONE : View.VISIBLE);
binding.threadTitle.setTypeface(binding.threadTitle.getTypeface(), read ? Typeface.NORMAL : Typeface.BOLD);
binding.subtitle.setTypeface(binding.subtitle.getTypeface(), read ? Typeface.NORMAL : Typeface.BOLD);
binding.threadTitle.setTypeface(null, read ? Typeface.NORMAL : Typeface.BOLD);
binding.subtitle.setTypeface(null, read ? Typeface.NORMAL : Typeface.BOLD);
}
}

View file

@ -115,7 +115,8 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentMod
owner.getString("profile_pic_url"),
null,
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
false, false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null);
false, false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null,
null, null);
final JSONObject likedBy = childComment.optJSONObject("edge_liked_by");
commentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID),
childComment.getString("text"),
@ -193,7 +194,8 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentMod
null,
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
owner.optBoolean("is_verified"),
false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null);
false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null, null,
null);
final JSONObject likedBy = comment.optJSONObject("edge_liked_by");
final String commentId = comment.getString(Constants.EXTRAS_ID);
final CommentModel commentModel = new CommentModel(commentId,
@ -235,7 +237,7 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentMod
null,
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
tempJsonObject.optBoolean("is_verified"), false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0,
null, null);
null, null, null, null, null);
tempJsonObject = childComment.optJSONObject("edge_liked_by");
childCommentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID),

View file

@ -1,139 +0,0 @@
package awais.instagrabber.asyncs;
import android.os.AsyncTask;
import android.util.Log;
import androidx.annotation.NonNull;
import org.json.JSONObject;
import java.net.HttpURLConnection;
import java.net.URL;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.NetworkUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
private static final String TAG = "GetActivityAsyncTask";
private final OnTaskCompleteListener onTaskCompleteListener;
public GetActivityAsyncTask(final OnTaskCompleteListener onTaskCompleteListener) {
this.onTaskCompleteListener = onTaskCompleteListener;
}
/*
This needs to be redone to fetch i inbox instead
Within inbox, data is (body JSON => counts)
Then we have these counts:
new_posts, activity_feed_dot_badge, relationships, campaign_notification
usertags, likes, comment_likes, shopping_notification, comments
photos_of_you (not sure about difference to usertags), requests
*/
protected NotificationCounts doInBackground(final String... cookiesArray) {
if (cookiesArray == null) return null;
final String cookie = cookiesArray[0];
if (TextUtils.isEmpty(cookie)) return null;
final long uid = CookieUtils.getUserIdFromCookie(cookie);
final String url = "https://www.instagram.com/graphql/query/?query_hash=0f318e8cfff9cc9ef09f88479ff571fb"
+ "&variables={\"id\":\"" + uid + "\"}";
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.BROWSER_UA));
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
final JSONObject data = new JSONObject(NetworkUtils.readFromConnection(urlConnection))
.getJSONObject("data")
.getJSONObject("user")
.getJSONObject("edge_activity_count")
.getJSONArray("edges")
.getJSONObject(0)
.getJSONObject("node");
return new NotificationCounts(
data.getInt("relationships"),
data.getInt("usertags"),
data.getInt("comments"),
data.getInt("comment_likes"),
data.getInt("likes")
);
} catch (Throwable ex) {
Log.e(TAG, "Error", ex);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
@Override
protected void onPostExecute(final NotificationCounts result) {
if (onTaskCompleteListener == null) return;
onTaskCompleteListener.onTaskComplete(result);
}
public static class NotificationCounts {
private final int relationshipsCount;
private final int userTagsCount;
private final int commentsCount;
private final int commentLikesCount;
private final int likesCount;
public NotificationCounts(final int relationshipsCount,
final int userTagsCount,
final int commentsCount,
final int commentLikesCount,
final int likesCount) {
this.relationshipsCount = relationshipsCount;
this.userTagsCount = userTagsCount;
this.commentsCount = commentsCount;
this.commentLikesCount = commentLikesCount;
this.likesCount = likesCount;
}
public int getRelationshipsCount() {
return relationshipsCount;
}
public int getUserTagsCount() {
return userTagsCount;
}
public int getCommentsCount() {
return commentsCount;
}
public int getCommentLikesCount() {
return commentLikesCount;
}
public int getLikesCount() {
return likesCount;
}
@NonNull
@Override
public String toString() {
return "NotificationCounts{" +
"relationshipsCount=" + relationshipsCount +
", userTagsCount=" + userTagsCount +
", commentsCount=" + commentsCount +
", commentLikesCount=" + commentLikesCount +
", likesCount=" + likesCount +
'}';
}
}
public interface OnTaskCompleteListener {
void onTaskComplete(final NotificationCounts result);
}
}

View file

@ -8,35 +8,35 @@ import java.util.List;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.repositories.responses.Notification;
import awais.instagrabber.webservices.NewsService;
import awais.instagrabber.webservices.ServiceCallback;
import awaisomereport.LogCollector;
import static awais.instagrabber.utils.Utils.logCollector;
public final class NotificationsFetcher extends AsyncTask<Void, Void, List<NotificationModel>> {
public final class NotificationsFetcher extends AsyncTask<Void, Void, List<Notification>> {
private static final String TAG = "NotificationsFetcher";
private final FetchListener<List<NotificationModel>> fetchListener;
private final FetchListener<List<Notification>> fetchListener;
private final NewsService newsService;
private final boolean markAsSeen;
private boolean fetchedWeb = false;
public NotificationsFetcher(final boolean markAsSeen,
final FetchListener<List<NotificationModel>> fetchListener) {
final FetchListener<List<Notification>> fetchListener) {
this.markAsSeen = markAsSeen;
this.fetchListener = fetchListener;
newsService = NewsService.getInstance();
}
@Override
protected List<NotificationModel> doInBackground(final Void... voids) {
List<NotificationModel> notificationModels = new ArrayList<>();
protected List<Notification> doInBackground(final Void... voids) {
List<Notification> notificationModels = new ArrayList<>();
newsService.fetchAppInbox(markAsSeen, new ServiceCallback<List<NotificationModel>>() {
newsService.fetchAppInbox(markAsSeen, new ServiceCallback<List<Notification>>() {
@Override
public void onSuccess(final List<NotificationModel> result) {
public void onSuccess(final List<Notification> result) {
if (result == null) return;
notificationModels.addAll(result);
if (fetchedWeb) {
@ -44,7 +44,7 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, List<Notif
}
else {
fetchedWeb = true;
newsService.fetchWebInbox(markAsSeen, this);
newsService.fetchWebInbox(this);
}
}

View file

@ -1,51 +0,0 @@
package awais.instagrabber.asyncs;
import android.os.AsyncTask;
import android.util.Log;
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import awais.instagrabber.models.StoryModel;
import awais.instagrabber.utils.NetworkUtils;
public class SeenAction extends AsyncTask<Void, Void, Void> {
private static final String TAG = "SeenAction";
private final String cookie;
private final StoryModel storyModel;
public SeenAction(final String cookie, final StoryModel storyModel) {
this.cookie = cookie;
this.storyModel = storyModel;
}
protected Void doInBackground(Void... voids) {
final String url = "https://www.instagram.com/stories/reel/seen";
try {
final String urlParameters = "reelMediaId=" + storyModel.getStoryMediaId().split("_")[0]
+ "&reelMediaOwnerId=" + storyModel.getUserId()
+ "&reelId=" + storyModel.getUserId()
+ "&reelMediaTakenAt=" + storyModel.getTimestamp()
+ "&viewSeenAt=" + storyModel.getTimestamp();
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
urlConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
urlConnection.connect();
Log.d(TAG, urlConnection.getResponseCode() + " " + NetworkUtils.readFromConnection(urlConnection));
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e(TAG, "Error", ex);
}
return null;
}
}

View file

@ -276,7 +276,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity();
tagsService = TagsService.getInstance();
storiesService = StoriesService.getInstance();
storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true);
}

View file

@ -270,7 +270,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity();
storiesService = StoriesService.getInstance();
storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true);
}

View file

@ -15,7 +15,9 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
@ -33,11 +35,13 @@ import awais.instagrabber.asyncs.NotificationsFetcher;
import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.requests.StoryViewerOptions;
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.Notification;
import awais.instagrabber.repositories.responses.NotificationArgs;
import awais.instagrabber.repositories.responses.NotificationImage;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.TextUtils;
@ -53,16 +57,36 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
public final class NotificationsViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "NotificationsViewer";
private AppCompatActivity fragmentActivity;
private FragmentNotificationsViewerBinding binding;
private SwipeRefreshLayout root;
private boolean shouldRefresh = true;
private NotificationViewModel notificationViewModel;
private FriendshipService friendshipService;
private MediaService mediaService;
private String csrfToken;
private NewsService newsService;
private String csrfToken, deviceUuid;
private String type;
private long targetId;
private Context context;
private final ServiceCallback<List<Notification>> cb = new ServiceCallback<List<Notification>>() {
@Override
public void onSuccess(final List<Notification> notificationModels) {
binding.swipeRefreshLayout.setRefreshing(false);
notificationViewModel.getList().postValue(notificationModels);
}
@Override
public void onFailure(final Throwable t) {
try {
binding.swipeRefreshLayout.setRefreshing(false);
Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
catch(Throwable e) {}
}
};
private final OnNotificationClickListener clickListener = new OnNotificationClickListener() {
@Override
public void onProfileClick(final String username) {
@ -70,14 +94,18 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
}
@Override
public void onPreviewClick(final NotificationModel model) {
public void onPreviewClick(final Notification model) {
final NotificationImage notificationImage = model.getArgs().getMedia().get(0);
final long mediaId = Long.valueOf(notificationImage.getId().split("_")[0]);
if (model.getType() == NotificationType.RESPONDED_STORY) {
final NavDirections action = NotificationsViewerFragmentDirections
.actionNotificationsViewerFragmentToStoryViewerFragment(StoryViewerOptions.forStory(model.getPostId(),
model.getUsername()));
.actionNotificationsViewerFragmentToStoryViewerFragment(
StoryViewerOptions.forStory(
mediaId,
model.getArgs().getUsername()));
NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(action);
} else {
mediaService.fetch(model.getPostId(), new ServiceCallback<Media>() {
mediaService.fetch(mediaId, new ServiceCallback<Media>() {
@Override
public void onSuccess(final Media feedModel) {
final PostViewV2Fragment fragment = PostViewV2Fragment
@ -95,13 +123,14 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
}
@Override
public void onNotificationClick(final NotificationModel model) {
public void onNotificationClick(final Notification model) {
if (model == null) return;
final String username = model.getUsername();
final NotificationArgs args = model.getArgs();
final String username = args.getUsername();
if (model.getType() == NotificationType.FOLLOW || model.getType() == NotificationType.AYML) {
openProfile(username);
} else {
final SpannableString title = new SpannableString(username + (TextUtils.isEmpty(model.getText()) ? "" : (":\n" + model.getText())));
final SpannableString title = new SpannableString(username + (TextUtils.isEmpty(args.getText()) ? "" : (":\n" + args.getText())));
title.setSpan(new RelativeSizeSpan(1.23f), 0, username.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
String[] commentDialogList;
@ -110,7 +139,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
getString(R.string.open_profile),
getString(R.string.view_story)
};
} else if (model.getPostId() > 0) {
} else if (args.getMedia() != null) {
commentDialogList = new String[]{
getString(R.string.open_profile),
getString(R.string.view_post)
@ -131,7 +160,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
break;
case 1:
if (model.getType() == NotificationType.REQUEST) {
friendshipService.approve(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
friendshipService.approve(args.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
onRefresh();
@ -148,7 +177,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
clickListener.onPreviewClick(model);
break;
case 2:
friendshipService.ignore(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
friendshipService.ignore(args.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
onRefresh();
@ -174,6 +203,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentActivity = (AppCompatActivity) requireActivity();
context = getContext();
if (context == null) return;
NotificationManagerCompat.from(context.getApplicationContext()).cancel(Constants.ACTIVITY_NOTIFICATION_ID);
@ -183,9 +213,10 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
}
mediaService = MediaService.getInstance(null, null, 0);
final long userId = CookieUtils.getUserIdFromCookie(cookie);
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
newsService = NewsService.getInstance();
}
@NonNull
@ -210,6 +241,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
private void init() {
final NotificationsViewerFragmentArgs fragmentArgs = NotificationsViewerFragmentArgs.fromBundle(getArguments());
type = fragmentArgs.getType();
targetId = fragmentArgs.getTargetId();
final Context context = getContext();
CookieUtils.setupCookies(settingsHelper.getString(Constants.COOKIE));
binding.swipeRefreshLayout.setOnRefreshListener(this);
@ -224,11 +256,13 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
@Override
public void onRefresh() {
binding.swipeRefreshLayout.setRefreshing(true);
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
switch (type) {
case "notif":
new NotificationsFetcher(true, new FetchListener<List<NotificationModel>>() {
if (actionBar != null) actionBar.setTitle(R.string.action_notif);
new NotificationsFetcher(true, new FetchListener<List<Notification>>() {
@Override
public void onResult(final List<NotificationModel> notificationModels) {
public void onResult(final List<Notification> notificationModels) {
binding.swipeRefreshLayout.setRefreshing(false);
notificationViewModel.getList().postValue(notificationModels);
}
@ -244,23 +278,12 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
break;
case "ayml":
final NewsService newsService = NewsService.getInstance();
newsService.fetchSuggestions(csrfToken, new ServiceCallback<List<NotificationModel>>() {
@Override
public void onSuccess(final List<NotificationModel> notificationModels) {
binding.swipeRefreshLayout.setRefreshing(false);
notificationViewModel.getList().postValue(notificationModels);
}
@Override
public void onFailure(final Throwable t) {
try {
binding.swipeRefreshLayout.setRefreshing(false);
Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
catch(Throwable e) {}
}
});
if (actionBar != null) actionBar.setTitle(R.string.action_ayml);
newsService.fetchSuggestions(csrfToken, deviceUuid, cb);
break;
case "chaining":
if (actionBar != null) actionBar.setTitle(R.string.action_ayml);
newsService.fetchChaining(targetId, cb);
break;
}
}

View file

@ -119,7 +119,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
fragmentActivity = (AppCompatActivity) requireActivity();
context = getContext();
if (context == null) return;
storiesService = StoriesService.getInstance();
storiesService = StoriesService.getInstance(null, 0L, null);
}
@NonNull

View file

@ -71,7 +71,6 @@ import awais.instagrabber.R;
import awais.instagrabber.adapters.StoriesAdapter;
import awais.instagrabber.asyncs.CreateThreadAction;
import awais.instagrabber.asyncs.PostFetcher;
import awais.instagrabber.asyncs.SeenAction;
import awais.instagrabber.customviews.helpers.SwipeGestureListener;
import awais.instagrabber.databinding.FragmentStoryViewerBinding;
import awais.instagrabber.fragments.main.ProfileFragmentDirections;
@ -151,17 +150,16 @@ public class StoryViewerFragment extends Fragment {
private DirectMessagesService directMessagesService;
private final String cookie = settingsHelper.getString(Constants.COOKIE);
private final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
private final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
private final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
private StoryViewerOptions options;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
fragmentActivity = (AppCompatActivity) requireActivity();
storiesService = StoriesService.getInstance();
if (csrfToken == null) return;
storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
setHasOptionsMenu(true);
}
@ -478,36 +476,32 @@ public class StoryViewerFragment extends Fragment {
poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
poll.getRightChoice() + " (" + poll.getRightCount() + ")"
}), (d, w) -> {
if (!TextUtils.isEmpty(cookie)) {
sticking = true;
storiesService.respondToPoll(
currentStory.getStoryMediaId().split("_")[0],
poll.getId(),
w,
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() {
@Override
public void onSuccess(final StoryStickerResponse result) {
sticking = false;
try {
poll.setMyChoice(w);
Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
}
catch (Exception ignored) {}
sticking = true;
storiesService.respondToPoll(
currentStory.getStoryMediaId().split("_")[0],
poll.getId(),
w,
new ServiceCallback<StoryStickerResponse>() {
@Override
public void onSuccess(final StoryStickerResponse result) {
sticking = false;
try {
poll.setMyChoice(w);
Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
}
catch (Exception ignored) {}
}
@Override
public void onFailure(final Throwable t) {
sticking = false;
Log.e(TAG, "Error responding", t);
try {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
catch (Exception ignored) {}
@Override
public void onFailure(final Throwable t) {
sticking = false;
Log.e(TAG, "Error responding", t);
try {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
});
}
catch (Exception ignored) {}
}
});
})
.setPositiveButton(R.string.cancel, null)
.show();
@ -525,8 +519,6 @@ public class StoryViewerFragment extends Fragment {
currentStory.getStoryMediaId().split("_")[0],
question.getId(),
input.getText().toString(),
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() {
@Override
public void onSuccess(final StoryStickerResponse result) {
@ -565,14 +557,12 @@ public class StoryViewerFragment extends Fragment {
new AlertDialog.Builder(context)
.setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion())
.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices), (d, w) -> {
if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) {
if (quiz.getMyChoice() == -1) {
sticking = true;
storiesService.respondToQuiz(
currentStory.getStoryMediaId().split("_")[0],
quiz.getId(),
w,
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() {
@Override
public void onSuccess(final StoryStickerResponse result) {
@ -643,8 +633,6 @@ public class StoryViewerFragment extends Fragment {
currentStory.getStoryMediaId().split("_")[0],
slider.getId(),
sliderValue,
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() {
@Override
public void onSuccess(final StoryStickerResponse result) {
@ -868,7 +856,7 @@ public class StoryViewerFragment extends Fragment {
binding.poll.setTag(poll);
question = currentStory.getQuestion();
binding.answer.setVisibility((question != null && !TextUtils.isEmpty(cookie)) ? View.VISIBLE : View.GONE);
binding.answer.setVisibility((question != null) ? View.VISIBLE : View.GONE);
binding.answer.setTag(question);
mentions = currentStory.getMentions();
@ -909,7 +897,11 @@ public class StoryViewerFragment extends Fragment {
actionBar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L)));
}
if (settingsHelper.getBoolean(MARK_AS_SEEN)) new SeenAction(cookie, currentStory).execute();
if (settingsHelper.getBoolean(MARK_AS_SEEN))
storiesService.seen(currentStory.getStoryMediaId(),
currentStory.getTimestamp(),
System.currentTimeMillis() / 1000,
null);
}
private void downloadStory() {
@ -947,7 +939,7 @@ public class StoryViewerFragment extends Fragment {
if (menuDownload != null) {
menuDownload.setVisible(true);
}
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) {
if (currentStory.canReply() && menuDm != null) {
menuDm.setVisible(true);
}
binding.progressView.setVisibility(View.GONE);
@ -980,7 +972,7 @@ public class StoryViewerFragment extends Fragment {
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) {
if (menuDownload != null) menuDownload.setVisible(true);
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie))
if (currentStory.canReply() && menuDm != null)
menuDm.setVisible(true);
binding.progressView.setVisibility(View.GONE);
}
@ -991,7 +983,7 @@ public class StoryViewerFragment extends Fragment {
@NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) {
if (menuDownload != null) menuDownload.setVisible(true);
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie))
if (currentStory.canReply() && menuDm != null)
menuDm.setVisible(true);
binding.progressView.setVisibility(View.VISIBLE);
}

View file

@ -259,7 +259,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity();
storiesService = StoriesService.getInstance();
storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true);
}

View file

@ -85,6 +85,7 @@ import awais.instagrabber.repositories.responses.FriendshipRestrictResponse;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.UserProfileContextLink;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.DownloadUtils;
@ -123,6 +124,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private HighlightsViewModel highlightsViewModel;
private MenuItem blockMenuItem;
private MenuItem restrictMenuItem;
private MenuItem chainingMenuItem;
private boolean highlightsFetching;
private boolean postsSetupDone = false;
private Set<Media> selectedFeedModels;
@ -306,7 +308,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
fragmentActivity = (MainActivity) requireActivity();
friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, userId) : null;
storiesService = isLoggedIn ? StoriesService.getInstance() : null;
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
@ -362,11 +364,31 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
inflater.inflate(R.menu.profile_menu, menu);
blockMenuItem = menu.findItem(R.id.block);
if (blockMenuItem != null) {
blockMenuItem.setVisible(false);
if (profileModel != null) {
blockMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie)));
blockMenuItem.setTitle(profileModel.getFriendshipStatus().isBlocking() ? R.string.unblock : R.string.block);
} else {
blockMenuItem.setVisible(false);
}
}
restrictMenuItem = menu.findItem(R.id.restrict);
if (restrictMenuItem != null) {
restrictMenuItem.setVisible(false);
if (profileModel != null) {
restrictMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie)));
restrictMenuItem.setTitle(profileModel.getFriendshipStatus().isRestricted() ? R.string.unrestrict : R.string.restrict);
}
else {
restrictMenuItem.setVisible(false);
}
}
chainingMenuItem = menu.findItem(R.id.chaining);
if (chainingMenuItem != null) {
if (profileModel != null) {
chainingMenuItem.setVisible(!Objects.equals(profileModel.getPk(), CookieUtils.getUserIdFromCookie(cookie)));
}
else {
chainingMenuItem.setVisible(false);
}
}
}
@ -431,11 +453,18 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
});
return true;
}
if (item.getItemId() == R.id.chaining) {
if (!isLoggedIn) return false;
final NavDirections navDirections = ProfileFragmentDirections.actionGlobalNotificationsViewerFragment("chaining", profileModel.getPk());
NavHostFragment.findNavController(this).navigate(navDirections);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onRefresh() {
profileDetailsBinding.countsBarrier.setVisibility(View.GONE);
profileDetailsBinding.mainProfileImage.setVisibility(View.INVISIBLE);
fetchProfileDetails();
}
@ -653,6 +682,8 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
profileDetailsBinding.mainProfileImage.setImageURI(profileModel.getProfilePicUrl());
profileDetailsBinding.mainProfileImage.setVisibility(View.VISIBLE);
profileDetailsBinding.countsBarrier.setVisibility(View.VISIBLE);
final long followersCount = profileModel.getFollowerCount();
final long followingCount = profileModel.getFollowingCount();
@ -691,7 +722,11 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
: profileModel.getFullName());
final String biography = profileModel.getBiography();
if (!TextUtils.isEmpty(biography)) {
if (TextUtils.isEmpty(biography)) {
profileDetailsBinding.mainBiography.setVisibility(View.GONE);
}
else {
profileDetailsBinding.mainBiography.setVisibility(View.VISIBLE);
profileDetailsBinding.mainBiography.setText(biography);
profileDetailsBinding.mainBiography.addOnHashtagListener(autoLinkItem -> {
final NavController navController = NavHostFragment.findNavController(this);
@ -756,6 +791,27 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
return true;
});
}
String profileContext = profileModel.getProfileContext();
if (TextUtils.isEmpty(profileContext)) {
profileDetailsBinding.profileContext.setVisibility(View.GONE);
}
else {
profileDetailsBinding.profileContext.setVisibility(View.VISIBLE);
final List<UserProfileContextLink> userProfileContextLinks = profileModel.getProfileContextLinks();
for (int i = 0; i < userProfileContextLinks.size(); i++) {
final UserProfileContextLink link = userProfileContextLinks.get(i);
if (link.getUsername() != null)
profileContext = profileContext.substring(0, link.getStart() + i)
+ "@" + profileContext.substring(link.getStart() + i);
}
profileDetailsBinding.profileContext.setText(profileContext);
profileDetailsBinding.profileContext.addOnMentionClickListener(autoLinkItem -> {
final String originalText = autoLinkItem.getOriginalText().trim();
navigateToProfile(originalText);
});
}
final String url = profileModel.getExternalUrl();
if (TextUtils.isEmpty(url)) {
profileDetailsBinding.mainUrl.setVisibility(View.GONE);
@ -830,13 +886,13 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
}
if (profileModel.getFriendshipStatus().isFollowing()) {
profileDetailsBinding.btnFollow.setText(R.string.unfollow);
profileDetailsBinding.btnFollow.setIconResource(R.drawable.ic_outline_person_add_disabled_24);
profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
} else if (profileModel.getFriendshipStatus().isOutgoingRequest()) {
profileDetailsBinding.btnFollow.setText(R.string.cancel);
profileDetailsBinding.btnFollow.setIconResource(R.drawable.ic_outline_person_add_disabled_24);
profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24);
} else {
profileDetailsBinding.btnFollow.setText(R.string.follow);
profileDetailsBinding.btnFollow.setIconResource(R.drawable.ic_outline_person_add_24);
profileDetailsBinding.btnFollow.setChipIconResource(R.drawable.ic_outline_person_add_24);
}
if (restrictMenuItem != null) {
restrictMenuItem.setVisible(true);
@ -854,15 +910,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
blockMenuItem.setTitle(R.string.block);
}
}
return;
}
if (!isReallyPrivate() && restrictMenuItem != null) {
restrictMenuItem.setVisible(true);
if (profileModel.getFriendshipStatus().isRestricted()) {
restrictMenuItem.setTitle(R.string.unrestrict);
} else {
restrictMenuItem.setTitle(R.string.restrict);
if (chainingMenuItem != null && !Objects.equals(profileId, myId)) {
chainingMenuItem.setVisible(true);
}
return;
}
}

View file

@ -134,12 +134,12 @@ public class MorePreferencesFragment extends BasePreferencesFragment {
screen.addPreference(getDivider(context));
if (isLoggedIn) {
screen.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> {
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif");
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("notif", 0l);
NavHostFragment.findNavController(this).navigate(navDirections);
return true;
}));
screen.addPreference(getPreference(R.string.action_ayml, R.drawable.ic_suggested_users, preference -> {
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml");
final NavDirections navDirections = MorePreferencesFragmentDirections.actionGlobalNotificationsViewerFragment("ayml", 0l);
NavHostFragment.findNavController(this).navigate(navDirections);
return true;
}));

View file

@ -1,79 +0,0 @@
package awais.instagrabber.models;
import androidx.annotation.NonNull;
import java.util.Date;
import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.utils.Utils;
public final class NotificationModel {
private final String id;
private final long userId;
private final String username;
private final String profilePicUrl;
private final long postId;
private final String previewUrl;
private final NotificationType type;
private final CharSequence text;
private final long timestamp;
public NotificationModel(final String id,
final String text,
final long timestamp,
final long userId,
final String username,
final String profilePicUrl,
final long postId,
final String previewUrl,
final NotificationType type) {
this.id = id;
this.text = text;
this.timestamp = timestamp;
this.userId = userId;
this.username = username;
this.profilePicUrl = profilePicUrl;
this.postId = postId;
this.previewUrl = previewUrl;
this.type = type;
}
public String getId() {
return id;
}
public CharSequence getText() {
return text;
}
public long getTimestamp() {
return timestamp;
}
@NonNull
public String getDateTime() {
return Utils.datetimeParser.format(new Date(timestamp * 1000L));
}
public long getUserId() {
return userId;
}
public String getUsername() {
return username;
}
public String getProfilePic() {
return profilePicUrl;
}
public long getPostId() {
return postId;
}
public String getPreviewPic() {
return previewUrl;
}
public NotificationType getType() { return type; }
}

View file

@ -2,6 +2,9 @@ package awais.instagrabber.repositories;
import java.util.Map;
import awais.instagrabber.repositories.responses.AymlResponse;
import awais.instagrabber.repositories.responses.NewsInboxResponse;
import awais.instagrabber.repositories.responses.UserSearchResponse;
import retrofit2.Call;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
@ -16,9 +19,12 @@ public interface NewsRepository {
Call<String> webInbox(@Header("User-Agent") String userAgent);
@GET("/api/v1/news/inbox/")
Call<String> appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen);
Call<NewsInboxResponse> appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen);
@FormUrlEncoded
@POST("/api/v1/discover/ayml/")
Call<String> getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map<String, String> form);
Call<AymlResponse> getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map<String, String> form);
@GET("/api/v1/discover/chaining/")
Call<UserSearchResponse> getChaining(@Header("User-Agent") String userAgent, @Query(value = "target_id") long targetId);
}

View file

@ -36,4 +36,8 @@ public interface StoriesRepository {
@Path("action") String action,
// story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer
@FieldMap Map<String, String> form);
@FormUrlEncoded
@POST("/api/v2/media/seen/")
Call<String> seen(@QueryMap Map<String, String> queryParams, @FieldMap Map<String, String> form);
}

View file

@ -0,0 +1,22 @@
package awais.instagrabber.repositories.responses;
import java.util.List;
public class AymlResponse {
private final AymlUserList newSuggestedUsers;
private final AymlUserList suggestedUsers;
public AymlResponse(final AymlUserList newSuggestedUsers,
final AymlUserList suggestedUsers) {
this.newSuggestedUsers = newSuggestedUsers;
this.suggestedUsers = suggestedUsers;
}
public AymlUserList getNewSuggestedUsers() {
return newSuggestedUsers;
}
public AymlUserList getSuggestedUsers() {
return suggestedUsers;
}
}

View file

@ -0,0 +1,34 @@
package awais.instagrabber.repositories.responses;
public class AymlUser {
private final User user;
private final String algorithm;
private final String socialContext;
private final String uuid;
public AymlUser(final User user,
final String algorithm,
final String socialContext,
final String uuid) {
this.user = user;
this.algorithm = algorithm;
this.socialContext = socialContext;
this.uuid = uuid;
}
public User getUser() {
return user;
}
public String getAlgorithm() {
return algorithm;
}
public String getSocialContext() {
return socialContext;
}
public String getUuid() {
return uuid;
}
}

View file

@ -0,0 +1,15 @@
package awais.instagrabber.repositories.responses;
import java.util.List;
public class AymlUserList {
private final List<AymlUser> suggestions;
public AymlUserList(final List<AymlUser> suggestions) {
this.suggestions = suggestions;
}
public List<AymlUser> getSuggestions() {
return suggestions;
}
}

View file

@ -0,0 +1,29 @@
package awais.instagrabber.repositories.responses;
import java.util.List;
public class NewsInboxResponse {
private final NotificationCounts counts;
private final List<Notification> newStories;
private final List<Notification> oldStories;
public NewsInboxResponse(final NotificationCounts counts,
final List<Notification> newStories,
final List<Notification> oldStories) {
this.counts = counts;
this.newStories = newStories;
this.oldStories = oldStories;
}
public NotificationCounts getCounts() {
return counts;
}
public List<Notification> getNewStories() {
return newStories;
}
public List<Notification> getOldStories() {
return oldStories;
}
}

View file

@ -0,0 +1,29 @@
package awais.instagrabber.repositories.responses;
import awais.instagrabber.models.enums.NotificationType;
public class Notification {
private final NotificationArgs args;
private final String storyType;
private final String pk;
public Notification(final NotificationArgs args,
final String storyType,
final String pk) {
this.args = args;
this.storyType = storyType;
this.pk = pk;
}
public NotificationArgs getArgs() {
return args;
}
public NotificationType getType() {
return NotificationType.valueOfType(storyType);
}
public String getPk() {
return pk;
}
}

View file

@ -0,0 +1,93 @@
package awais.instagrabber.repositories.responses;
import androidx.annotation.NonNull;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.util.Log;
import awais.instagrabber.utils.Utils;
public class NotificationArgs {
private final String text;
private final String richText;
private final long profileId;
private final String profileImage;
private final List<NotificationImage> media;
private final double timestamp;
private final String profileName;
private final String fullName; // for AYML, not naturally generated
private final boolean isVerified; // mostly for AYML, not sure about notif
public NotificationArgs(final String text,
final String richText, // for AYML, this is the algorithm
final long profileId,
final String profileImage,
final List<NotificationImage> media,
final double timestamp,
final String profileName,
final String fullName,
final boolean isVerified) {
this.text = text;
this.richText = richText;
this.profileId = profileId;
this.profileImage = profileImage;
this.media = media;
this.timestamp = timestamp;
this.profileName = profileName;
this.fullName = fullName;
this.isVerified = isVerified;
}
public String getText() {
return text == null ? cleanRichText(richText) : text;
}
public long getUserId() {
return profileId;
}
public String getProfilePic() {
return profileImage;
}
public String getUsername() {
return profileName;
}
public String getFullName() {
return fullName;
}
public List<NotificationImage> getMedia() {
return media;
}
public double getTimestamp() {
return timestamp;
}
public boolean isVerified() {
return isVerified;
}
@NonNull
public String getDateTime() {
return Utils.datetimeParser.format(new Date(Math.round(timestamp * 1000)));
}
private String cleanRichText(final String raw) {
if (raw == null) return null;
final Matcher matcher = Pattern.compile("\\{[\\p{L}\\d._]+\\|000000\\|1\\|user\\?id=\\d+\\}").matcher(raw);
String result = raw;
while (matcher.find()) {
final String richObject = raw.substring(matcher.start(), matcher.end());
final String username = richObject.split("\\|")[0].substring(1);
result = result.replace(richObject, username);
}
return result;
}
}

View file

@ -0,0 +1,57 @@
package awais.instagrabber.repositories.responses;
import androidx.annotation.NonNull;
public class NotificationCounts {
private final int commentLikes;
private final int usertags;
private final int likes;
private final int comments;
private final int relationships;
private final int photosOfYou;
private final int requests;
public NotificationCounts(final int commentLikes,
final int usertags,
final int likes,
final int comments,
final int relationships,
final int photosOfYou,
final int requests) {
this.commentLikes = commentLikes;
this.usertags = usertags;
this.likes = likes;
this.comments = comments;
this.relationships = relationships;
this.photosOfYou = photosOfYou;
this.requests = requests;
}
public int getRelationshipsCount() {
return relationships;
}
public int getUserTagsCount() {
return usertags;
}
public int getCommentsCount() {
return comments;
}
public int getCommentLikesCount() {
return commentLikes;
}
public int getLikesCount() {
return likes;
}
public int getPOYCount() {
return photosOfYou;
}
public int getRequestsCount() {
return requests;
}
}

View file

@ -0,0 +1,19 @@
package awais.instagrabber.repositories.responses;
public class NotificationImage {
private final String id;
private final String image;
public NotificationImage(final String id, final String image) {
this.id = id;
this.image = image;
}
public String getId() {
return id;
}
public String getImage() {
return image;
}
}

View file

@ -1,6 +1,7 @@
package awais.instagrabber.repositories.responses;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
public class User implements Serializable {
@ -27,7 +28,9 @@ public class User implements Serializable {
private final long usertagsCount;
private final String publicEmail;
private final HdProfilePicUrlInfo hdProfilePicUrlInfo;
private final String profileContext;
private final List<UserProfileContextLink> profileContextLinksWithUserIds;
private final String socialContext;
public User(final long pk,
final String username,
@ -51,7 +54,10 @@ public class User implements Serializable {
final String externalUrl,
final long usertagsCount,
final String publicEmail,
final HdProfilePicUrlInfo hdProfilePicUrlInfo) {
final HdProfilePicUrlInfo hdProfilePicUrlInfo,
final String profileContext,
final List<UserProfileContextLink> profileContextLinksWithUserIds,
final String socialContext) {
this.pk = pk;
this.username = username;
this.fullName = fullName;
@ -75,6 +81,9 @@ public class User implements Serializable {
this.usertagsCount = usertagsCount;
this.publicEmail = publicEmail;
this.hdProfilePicUrlInfo = hdProfilePicUrlInfo;
this.profileContext = profileContext;
this.profileContextLinksWithUserIds = profileContextLinksWithUserIds;
this.socialContext = socialContext;
}
public long getPk() {
@ -173,46 +182,17 @@ public class User implements Serializable {
return publicEmail;
}
// public boolean isReallyPrivate() {
// final FriendshipStatus friendshipStatus = getFriendshipStatus();
// !user.optBoolean("followed_by_viewer") && (id != uid && isPrivate)
// }
public String getProfileContext() {
return profileContext;
}
// public static User fromProfileModel(final ProfileModel profileModel) {
// return new User(
// Long.parseLong(profileModel.getId()),
// profileModel.getUsername(),
// profileModel.getName(),
// profileModel.isPrivate(),
// profileModel.getSdProfilePic(),
// null,
// new FriendshipStatus(
// profileModel.isFollowing(),
// false,
// profileModel.isBlocked(),
// false,
// profileModel.isPrivate(),
// false,
// profileModel.isRequested(),
// false,
// profileModel.isRestricted(),
// false),
// profileModel.isVerified(),
// false,
// false,
// false,
// false,
// null,
// null,
// profileModel.getPostCount(),
// profileModel.getFollowersCount(),
// profileModel.getFollowingCount(),
// 0,
// profileModel.getBiography(),
// profileModel.getUrl(),
// 0,
// null);
// }
public String getSocialContext() {
return socialContext;
}
public List<UserProfileContextLink> getProfileContextLinks() {
return profileContextLinksWithUserIds;
}
@Override

View file

@ -1,49 +0,0 @@
package awais.instagrabber.repositories.responses;
public class UserInfo {
private final long pk;
private final String username, fullName, profilePicUrl, hdProfilePicUrl;
public UserInfo(final long pk,
final String username,
final String fullName,
final String profilePicUrl,
final String hdProfilePicUrl) {
this.pk = pk;
this.username = username;
this.fullName = fullName;
this.profilePicUrl = profilePicUrl;
this.hdProfilePicUrl = hdProfilePicUrl;
}
public long getPk() {
return pk;
}
public String getUsername() {
return username;
}
public String getFullName() {
return fullName;
}
public String getProfilePicUrl() {
return profilePicUrl;
}
public String getHDProfilePicUrl() {
return hdProfilePicUrl;
}
@Override
public String toString() {
return "UserInfo{" +
"uid='" + pk + '\'' +
", username='" + username + '\'' +
", fullName='" + fullName + '\'' +
", profilePicUrl='" + profilePicUrl + '\'' +
", hdProfilePicUrl='" + hdProfilePicUrl + '\'' +
'}';
}
}

View file

@ -0,0 +1,21 @@
package awais.instagrabber.repositories.responses;
public class UserProfileContextLink {
private final String username;
private final int start;
private final int end;
public UserProfileContextLink(final String username, final int start, final int end) {
this.username = username;
this.start = start;
this.end = end;
}
public String getUsername() {
return username;
}
public int getStart() {
return start;
}
}

View file

@ -18,8 +18,6 @@ import java.util.List;
import awais.instagrabber.R;
import awais.instagrabber.activities.MainActivity;
import awais.instagrabber.asyncs.GetActivityAsyncTask.NotificationCounts;
import awais.instagrabber.asyncs.GetActivityAsyncTask.OnTaskCompleteListener;
import awais.instagrabber.utils.Constants;
import static awais.instagrabber.utils.Utils.settingsHelper;
@ -30,7 +28,7 @@ public class ActivityCheckerService extends Service {
private static final int DELAY_MILLIS = 60000;
private Handler handler;
private OnTaskCompleteListener onTaskCompleteListener;
// private OnTaskCompleteListener onTaskCompleteListener;
private NotificationManagerCompat notificationManager;
private final IBinder binder = new LocalBinder();
@ -50,6 +48,7 @@ public class ActivityCheckerService extends Service {
public void onCreate() {
notificationManager = NotificationManagerCompat.from(getApplicationContext());
handler = new Handler();
/*
onTaskCompleteListener = result -> {
// Log.d(TAG, "onTaskCompleteListener: result: " + result);
try {
@ -62,20 +61,12 @@ public class ActivityCheckerService extends Service {
handler.postDelayed(runnable, DELAY_MILLIS);
}
};
*/
}
@Override
public IBinder onBind(Intent intent) {
startChecking();
// Uncomment to test notifications
// final String notificationString = getNotificationString(new NotificationCounts(
// 1,
// 2,
// 3,
// 4,
// 5
// ));
// showNotification(notificationString);
return binder;
}
@ -93,6 +84,7 @@ public class ActivityCheckerService extends Service {
handler.removeCallbacks(runnable);
}
/*
private String getNotificationString(final NotificationCounts result) {
final List<String> list = new ArrayList<>();
if (result.getRelationshipsCount() != 0) {
@ -113,6 +105,7 @@ public class ActivityCheckerService extends Service {
if (list.isEmpty()) return null;
return TextUtils.join(", ", list);
}
*/
private void showNotification(final String notificationString) {
final Notification notification = new NotificationCompat.Builder(this, Constants.ACTIVITY_CHANNEL_ID)

View file

@ -781,7 +781,8 @@ public final class ResponseBodyUtils {
null,
friendshipStatus,
owner.optBoolean("is_verified"),
false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null);
false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null,
null, null, null);
}
final String id = feedItem.getString(Constants.EXTRAS_ID);
final ImageVersions2 imageVersions2 = new ImageVersions2(

View file

@ -5,12 +5,12 @@ import androidx.lifecycle.ViewModel;
import java.util.List;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.repositories.responses.Notification;
public class NotificationViewModel extends ViewModel {
private MutableLiveData<List<NotificationModel>> list;
private MutableLiveData<List<Notification>> list;
public MutableLiveData<List<NotificationModel>> getList() {
public MutableLiveData<List<Notification>> getList() {
if (list == null) {
list = new MutableLiveData<>();
}

View file

@ -243,6 +243,9 @@ public class GraphQLService extends BaseService {
null,
0,
null,
null,
null,
null,
null
));
// userModels.add(new ProfileModel(userObject.optBoolean("is_private"),
@ -334,6 +337,9 @@ public class GraphQLService extends BaseService {
url,
0,
null,
null,
null,
null,
null));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);

View file

@ -9,17 +9,24 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.NewsRepository;
import awais.instagrabber.repositories.responses.AymlResponse;
import awais.instagrabber.repositories.responses.AymlUser;
import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.NewsInboxResponse;
import awais.instagrabber.repositories.responses.Notification;
import awais.instagrabber.repositories.responses.NotificationArgs;
import awais.instagrabber.repositories.responses.NotificationImage;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
import retrofit2.Call;
@ -52,48 +59,31 @@ public class NewsService extends BaseService {
}
public void fetchAppInbox(final boolean markAsSeen,
final ServiceCallback<List<NotificationModel>> callback) {
final List<NotificationModel> result = new ArrayList<>();
final Call<String> request = repository.appInbox(appUa, markAsSeen);
request.enqueue(new Callback<String>() {
final ServiceCallback<List<Notification>> callback) {
final Call<NewsInboxResponse> request = repository.appInbox(appUa, markAsSeen);
request.enqueue(new Callback<NewsInboxResponse>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
final String body = response.body();
public void onResponse(@NonNull final Call<NewsInboxResponse> call, @NonNull final Response<NewsInboxResponse> response) {
final NewsInboxResponse body = response.body();
if (body == null) {
callback.onSuccess(null);
return;
}
try {
final JSONObject jsonObject = new JSONObject(body);
final JSONArray oldStories = jsonObject.getJSONArray("old_stories"),
newStories = jsonObject.getJSONArray("new_stories");
for (int j = 0; j < newStories.length(); ++j) {
final NotificationModel newsItem = parseNewsItem(newStories.getJSONObject(j));
if (newsItem != null) result.add(newsItem);
}
for (int i = 0; i < oldStories.length(); ++i) {
final NotificationModel newsItem = parseNewsItem(oldStories.getJSONObject(i));
if (newsItem != null) result.add(newsItem);
}
callback.onSuccess(result);
} catch (JSONException e) {
callback.onFailure(e);
}
final List<Notification> result = new ArrayList<>();
result.addAll(body.getNewStories());
result.addAll(body.getOldStories());
callback.onSuccess(result);
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
public void onFailure(@NonNull final Call<NewsInboxResponse> call, @NonNull final Throwable t) {
callback.onFailure(t);
// Log.e(TAG, "onFailure: ", t);
}
});
}
public void fetchWebInbox(final boolean markAsSeen,
final ServiceCallback<List<NotificationModel>> callback) {
public void fetchWebInbox(final ServiceCallback<List<Notification>> callback) {
final Call<String> request = repository.webInbox(browserUa);
request.enqueue(new Callback<String>() {
@Override
@ -104,7 +94,7 @@ public class NewsService extends BaseService {
return;
}
try {
final List<NotificationModel> result = new ArrayList<>();
final List<Notification> result = new ArrayList<>();
final JSONObject page = new JSONObject(body)
.getJSONObject("graphql")
.getJSONObject("user");
@ -124,16 +114,25 @@ public class NewsService extends BaseService {
final NotificationType notificationType = NotificationType.valueOfType(type);
if (notificationType == null) continue;
final JSONObject user = data.getJSONObject("user");
result.add(new NotificationModel(
data.getString(Constants.EXTRAS_ID),
data.optString("text"), // comments or mentions
data.getLong("timestamp"),
user.getLong("id"),
user.getString("username"),
user.getString("profile_pic_url"),
!data.isNull("media") ? Long.valueOf(data.getJSONObject("media").getString("id").split("_")[0]) : 0,
data.has("media") ? data.getJSONObject("media").getString("thumbnail_src") : null,
notificationType));
result.add(new Notification(
new NotificationArgs(
data.optString("text"),
null,
user.getLong(Constants.EXTRAS_ID),
user.getString("profile_pic_url"),
data.isNull("media") ? null : Collections.singletonList(new NotificationImage(
data.getJSONObject("media").getString("id"),
data.getJSONObject("media").getString("thumbnail_src")
)),
data.getLong("timestamp"),
user.getString("username"),
null,
false
),
type,
data.getString(Constants.EXTRAS_ID)
));
}
}
@ -144,15 +143,21 @@ public class NewsService extends BaseService {
for (int i = 0; i < media.length(); ++i) {
data = media.optJSONObject(i).optJSONObject("node");
if (data == null) continue;
result.add(new NotificationModel(
data.getString(Constants.EXTRAS_ID),
data.optString("full_name"),
0L,
data.getLong(Constants.EXTRAS_ID),
data.getString("username"),
data.getString("profile_pic_url"),
0,
null, NotificationType.REQUEST));
result.add(new Notification(
new NotificationArgs(
null,
null,
data.getLong(Constants.EXTRAS_ID),
data.getString("profile_pic_url"),
null,
0L,
data.getString("username"),
data.optString("full_name"),
data.optBoolean("is_verified")
),
"REQUEST",
data.getString(Constants.EXTRAS_ID)
));
}
}
callback.onSuccess(result);
@ -169,40 +174,9 @@ public class NewsService extends BaseService {
});
}
private NotificationModel parseNewsItem(final JSONObject itemJson) throws JSONException {
if (itemJson == null) return null;
final String type = itemJson.getString("story_type");
final NotificationType notificationType = NotificationType.valueOfType(type);
if (notificationType == null) {
if (BuildConfig.DEBUG) Log.d("austin_debug", "unhandled news type: " + itemJson);
return null;
}
final JSONObject data = itemJson.getJSONObject("args");
return new NotificationModel(
data.getString("tuuid"),
data.has("text") ? data.getString("text") : cleanRichText(data.optString("rich_text", "")),
data.getLong("timestamp"),
data.getLong("profile_id"),
data.getString("profile_name"),
data.getString("profile_image"),
!data.isNull("media") ? Long.valueOf(data.getJSONArray("media").getJSONObject(0).getString("id").split("_")[0]) : 0,
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null,
notificationType);
}
private String cleanRichText(final String raw) {
final Matcher matcher = Pattern.compile("\\{[\\p{L}\\d._]+\\|000000\\|1\\|user\\?id=\\d+\\}").matcher(raw);
String result = raw;
while (matcher.find()) {
final String richObject = raw.substring(matcher.start(), matcher.end());
final String username = richObject.split("\\|")[0].substring(1);
result = result.replace(richObject, username);
}
return result;
}
public void fetchSuggestions(final String csrfToken,
final ServiceCallback<List<NotificationModel>> callback) {
final String deviceUuid,
final ServiceCallback<List<Notification>> callback) {
final Map<String, String> form = new HashMap<>();
form.put("_uuid", UUID.randomUUID().toString());
form.put("_csrftoken", csrfToken);
@ -210,57 +184,88 @@ public class NewsService extends BaseService {
form.put("device_id", UUID.randomUUID().toString());
form.put("module", "discover_people");
form.put("paginate", "false");
final Call<String> request = repository.getAyml(appUa, form);
request.enqueue(new Callback<String>() {
final Call<AymlResponse> request = repository.getAyml(appUa, form);
request.enqueue(new Callback<AymlResponse>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
final String body = response.body();
public void onResponse(@NonNull final Call<AymlResponse> call, @NonNull final Response<AymlResponse> response) {
final AymlResponse body = response.body();
if (body == null) {
callback.onSuccess(null);
return;
}
try {
final List<NotificationModel> result = new ArrayList<>();
final JSONObject jsonObject = new JSONObject(body);
final JSONArray oldStories = jsonObject.getJSONObject("suggested_users").getJSONArray("suggestions"),
newStories = jsonObject.getJSONObject("new_suggested_users").getJSONArray("suggestions");
final List<AymlUser> aymlUsers = new ArrayList<>();
aymlUsers.addAll(body.getNewSuggestedUsers().getSuggestions());
aymlUsers.addAll(body.getSuggestedUsers().getSuggestions());
for (int j = 0; j < newStories.length(); ++j) {
final NotificationModel newsItem = parseAymlItem(newStories.getJSONObject(j));
if (newsItem != null) result.add(newsItem);
}
for (int i = 0; i < oldStories.length(); ++i) {
final NotificationModel newsItem = parseAymlItem(oldStories.getJSONObject(i));
if (newsItem != null) result.add(newsItem);
}
callback.onSuccess(result);
} catch (JSONException e) {
callback.onFailure(e);
}
final List<Notification> newsItems = aymlUsers.stream()
.map(i -> {
final User u = i.getUser();
return new Notification(
new NotificationArgs(
i.getSocialContext(),
i.getAlgorithm(),
u.getPk(),
u.getProfilePicUrl(),
null,
0L,
u.getUsername(),
u.getFullName(),
u.isVerified()
),
"AYML",
i.getUuid()
);
})
.collect(Collectors.toList());
callback.onSuccess(newsItems);
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
public void onFailure(@NonNull final Call<AymlResponse> call, @NonNull final Throwable t) {
callback.onFailure(t);
// Log.e(TAG, "onFailure: ", t);
}
});
}
private NotificationModel parseAymlItem(final JSONObject itemJson) throws JSONException {
if (itemJson == null) return null;
final JSONObject data = itemJson.getJSONObject("user");
return new NotificationModel(
itemJson.getString("uuid"),
itemJson.getString("social_context"),
0L,
data.getLong("pk"),
data.getString("username"),
data.getString("profile_pic_url"),
0,
data.getString("full_name"), // just borrowing this field
NotificationType.AYML);
public void fetchChaining(final long targetId, final ServiceCallback<List<Notification>> callback) {
final Call<UserSearchResponse> request = repository.getChaining(appUa, targetId);
request.enqueue(new Callback<UserSearchResponse>() {
@Override
public void onResponse(@NonNull final Call<UserSearchResponse> call, @NonNull final Response<UserSearchResponse> response) {
final UserSearchResponse body = response.body();
if (body == null) {
callback.onSuccess(null);
return;
}
final List<Notification> newsItems = body.getUsers().stream()
.map(u -> {
return new Notification(
new NotificationArgs(
u.getSocialContext(),
null,
u.getPk(),
u.getProfilePicUrl(),
null,
0L,
u.getUsername(),
u.getFullName(),
u.isVerified()
),
"AYML",
u.getProfilePicId() // placeholder
);
})
.collect(Collectors.toList());
callback.onSuccess(newsItems);
}
@Override
public void onFailure(@NonNull final Call<UserSearchResponse> call, @NonNull final Throwable t) {
callback.onFailure(t);
// Log.e(TAG, "onFailure: ", t);
}
});
}
}

View file

@ -14,6 +14,7 @@ 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.FeedStoryModel;
@ -36,20 +37,45 @@ import retrofit2.Retrofit;
public class StoriesService extends BaseService {
private static final String TAG = "StoriesService";
private final StoriesRepository repository;
private static StoriesService instance;
private StoriesService() {
private final StoriesRepository repository;
private final String csrfToken;
private final long userId;
private final String deviceUuid;
private StoriesService(@NonNull final String csrfToken,
final long userId,
@NonNull final String deviceUuid) {
this.csrfToken = csrfToken;
this.userId = userId;
this.deviceUuid = deviceUuid;
final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://i.instagram.com")
.build();
repository = retrofit.create(StoriesRepository.class);
}
public static StoriesService getInstance() {
if (instance == null) {
instance = new StoriesService();
public String getCsrfToken() {
return csrfToken;
}
public long getUserId() {
return userId;
}
public String getDeviceUuid() {
return deviceUuid;
}
public static StoriesService getInstance(final String csrfToken,
final long userId,
final String deviceUuid) {
if (instance == null
|| !Objects.equals(instance.getCsrfToken(), csrfToken)
|| !Objects.equals(instance.getUserId(), userId)
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid)) {
instance = new StoriesService(csrfToken, userId, deviceUuid);
}
return instance;
}
@ -146,6 +172,9 @@ public class StoriesService extends BaseService {
null,
0,
null,
null,
null,
null,
null
);
final String id = node.getString("id");
@ -205,6 +234,9 @@ public class StoriesService extends BaseService {
null,
0,
null,
null,
null,
null,
null
);
final String id = node.getString("id");
@ -390,13 +422,11 @@ public class StoriesService extends BaseService {
final String action,
final String arg1,
final String arg2,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("_uuid", deviceUuid);
form.put("mutation_token", UUID.randomUUID().toString());
form.put("client_context", UUID.randomUUID().toString());
form.put("radio_type", "wifi-none");
@ -427,39 +457,67 @@ public class StoriesService extends BaseService {
public void respondToQuestion(final String storyId,
final String stickerId,
final String answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback);
respondToSticker(storyId, stickerId, "story_question_response", "response", answer, callback);
}
// QuizAction.java
public void respondToQuiz(final String storyId,
final String stickerId,
final int answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), userId, csrfToken, callback);
respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), callback);
}
// VoteAction.java
public void respondToPoll(final String storyId,
final String stickerId,
final int answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), userId, csrfToken, callback);
respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), callback);
}
public void respondToSlider(final String storyId,
final String stickerId,
final double answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback);
respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), callback);
}
public void seen(final String storyMediaId,
final long takenAt,
final long seenAt,
final ServiceCallback<String> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", deviceUuid);
form.put("container_module", "feed_timeline");
final Map<String, Object> reelsForm = new HashMap<>();
reelsForm.put(storyMediaId, Collections.singletonList(takenAt + "_" + seenAt));
form.put("reels", reelsForm);
final Map<String, String> signedForm = Utils.sign(form);
final Map<String, String> queryMap = new HashMap<>();
queryMap.put("reel", "1");
queryMap.put("live_vod", "0");
final Call<String> request = repository.seen(queryMap, signedForm);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call,
@NonNull final Response<String> response) {
if (callback != null) {
callback.onSuccess(response.body());
}
}
@Override
public void onFailure(@NonNull final Call<String> call,
@NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
}
@Nullable