From 5421bb4592fd84b7bf51ba2ede85244cc6609b99 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 4 Mar 2021 12:33:59 -0500 Subject: [PATCH 1/7] fix story seen --- .../awais/instagrabber/asyncs/SeenAction.java | 51 ---------- .../fragments/HashTagFragment.java | 2 +- .../fragments/LocationFragment.java | 2 +- .../fragments/StoryListViewerFragment.java | 2 +- .../fragments/StoryViewerFragment.java | 82 ++++++++-------- .../fragments/main/FeedFragment.java | 2 +- .../fragments/main/ProfileFragment.java | 2 +- .../repositories/StoriesRepository.java | 4 + .../webservices/StoriesService.java | 95 ++++++++++++++----- 9 files changed, 119 insertions(+), 123 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/SeenAction.java diff --git a/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java b/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java deleted file mode 100644 index 7656369d..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java +++ /dev/null @@ -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 { - 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; - } -} diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 12b9b413..550d43e1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -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); } diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 49e23159..4c1c9618 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -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); } diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java index 880af8f5..d71a7cfb 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java @@ -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 diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index ea38abe8..4a14927a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -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() { - @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() { + @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() { @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() { @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() { @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); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 54f6ea25..f4b8d47e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -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); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 3a7586ed..2ead6157 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -307,7 +307,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())); diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java index 6eaa83ba..766649c4 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java @@ -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 form); + + @FormUrlEncoded + @POST("/api/v2/media/seen/") + Call seen(@QueryMap Map queryParams, @FieldMap Map form); } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index bc6ca65a..3f84226c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -14,7 +14,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; +import java.util.Objects; import java.util.UUID; import awais.instagrabber.models.FeedStoryModel; @@ -37,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; } @@ -391,13 +416,11 @@ public class StoriesService extends BaseService { final String action, final String arg1, final String arg2, - final long userId, - final String csrfToken, final ServiceCallback callback) { final Map 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"); @@ -428,39 +451,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 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 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 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 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 callback) { + final Map form = new HashMap<>(); + form.put("_csrftoken", csrfToken); + form.put("_uid", userId); + form.put("_uuid", deviceUuid); + form.put("container_module", "feed_timeline"); + final Map reelsForm = new HashMap<>(); + reelsForm.put(storyMediaId, Collections.singletonList(takenAt + "_" + seenAt)); + form.put("reels", reelsForm); + final Map signedForm = Utils.sign(form); + final Map queryMap = new HashMap<>(); + queryMap.put("reel", "1"); + queryMap.put("live_vod", "0"); + final Call request = repository.seen(queryMap, signedForm); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, + @NonNull final Response response) { + if (callback != null) { + callback.onSuccess(response.body()); + } + } + + @Override + public void onFailure(@NonNull final Call call, + @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); } @Nullable From 7acd5faefd5ff39674f1af67c87da67b27becd92 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 4 Mar 2021 15:27:46 -0500 Subject: [PATCH 2/7] notification backend revamp --- .../adapters/NotificationsAdapter.java | 35 +-- .../viewholder/NotificationViewHolder.java | 31 +-- .../asyncs/GetActivityAsyncTask.java | 139 ------------ .../asyncs/NotificationsFetcher.java | 18 +- .../NotificationsViewerFragment.java | 37 ++-- .../models/NotificationModel.java | 79 ------- .../repositories/NewsRepository.java | 6 +- .../repositories/responses/AymlResponse.java | 22 ++ .../repositories/responses/AymlUser.java | 34 +++ .../repositories/responses/AymlUserList.java | 15 ++ .../responses/NewsInboxResponse.java | 29 +++ .../repositories/responses/Notification.java | 29 +++ .../responses/NotificationArgs.java | 86 ++++++++ .../responses/NotificationCounts.java | 57 +++++ .../responses/NotificationImage.java | 19 ++ .../repositories/responses/UserInfo.java | 49 ----- .../services/ActivityCheckerService.java | 17 +- .../viewmodels/NotificationViewModel.java | 6 +- .../instagrabber/webservices/NewsService.java | 205 +++++++----------- 19 files changed, 452 insertions(+), 461 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java delete mode 100755 app/src/main/java/awais/instagrabber/models/NotificationModel.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/AymlResponse.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/AymlUser.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/AymlUserList.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/Notification.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java delete mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/UserInfo.java diff --git a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java index 394c2374..8a5c3a4b 100644 --- a/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/NotificationsAdapter.java @@ -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 { +public final class NotificationsAdapter extends ListAdapter { private final OnNotificationClickListener notificationClickListener; - private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { + private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { @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 list, @Nullable final Runnable commitCallback) { + public void submitList(@Nullable final List list, @Nullable final Runnable commitCallback) { if (list == null) { super.submitList(null, commitCallback); return; @@ -61,7 +62,7 @@ public final class NotificationsAdapter extends ListAdapter list) { + public void submitList(@Nullable final List list) { if (list == null) { super.submitList(null); return; @@ -69,8 +70,10 @@ public final class NotificationsAdapter extends ListAdapter sort(final List list) { - final List listCopy = new ArrayList<>(list); + private List sort(final List list) { + final List 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 { 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); diff --git a/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java b/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java deleted file mode 100644 index 13a88ee4..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/GetActivityAsyncTask.java +++ /dev/null @@ -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 { - 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); - } -} diff --git a/app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java index 714a2793..89729909 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/NotificationsFetcher.java @@ -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> { +public final class NotificationsFetcher extends AsyncTask> { private static final String TAG = "NotificationsFetcher"; - private final FetchListener> fetchListener; + private final FetchListener> fetchListener; private final NewsService newsService; private final boolean markAsSeen; private boolean fetchedWeb = false; public NotificationsFetcher(final boolean markAsSeen, - final FetchListener> fetchListener) { + final FetchListener> fetchListener) { this.markAsSeen = markAsSeen; this.fetchListener = fetchListener; newsService = NewsService.getInstance(); } @Override - protected List doInBackground(final Void... voids) { - List notificationModels = new ArrayList<>(); + protected List doInBackground(final Void... voids) { + List notificationModels = new ArrayList<>(); - newsService.fetchAppInbox(markAsSeen, new ServiceCallback>() { + newsService.fetchAppInbox(markAsSeen, new ServiceCallback>() { @Override - public void onSuccess(final List result) { + public void onSuccess(final List result) { if (result == null) return; notificationModels.addAll(result); if (fetchedWeb) { @@ -44,7 +44,7 @@ public final class NotificationsFetcher extends AsyncTask() { + mediaService.fetch(mediaId, new ServiceCallback() { @Override public void onSuccess(final Media feedModel) { final PostViewV2Fragment fragment = PostViewV2Fragment @@ -95,13 +101,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 +117,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 +138,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe break; case 1: if (model.getType() == NotificationType.REQUEST) { - friendshipService.approve(model.getUserId(), new ServiceCallback() { + friendshipService.approve(args.getUserId(), new ServiceCallback() { @Override public void onSuccess(final FriendshipChangeResponse result) { onRefresh(); @@ -148,7 +155,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe clickListener.onPreviewClick(model); break; case 2: - friendshipService.ignore(model.getUserId(), new ServiceCallback() { + friendshipService.ignore(args.getUserId(), new ServiceCallback() { @Override public void onSuccess(final FriendshipChangeResponse result) { onRefresh(); @@ -226,9 +233,9 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe binding.swipeRefreshLayout.setRefreshing(true); switch (type) { case "notif": - new NotificationsFetcher(true, new FetchListener>() { + new NotificationsFetcher(true, new FetchListener>() { @Override - public void onResult(final List notificationModels) { + public void onResult(final List notificationModels) { binding.swipeRefreshLayout.setRefreshing(false); notificationViewModel.getList().postValue(notificationModels); } @@ -245,9 +252,9 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe break; case "ayml": final NewsService newsService = NewsService.getInstance(); - newsService.fetchSuggestions(csrfToken, new ServiceCallback>() { + newsService.fetchSuggestions(csrfToken, new ServiceCallback>() { @Override - public void onSuccess(final List notificationModels) { + public void onSuccess(final List notificationModels) { binding.swipeRefreshLayout.setRefreshing(false); notificationViewModel.getList().postValue(notificationModels); } diff --git a/app/src/main/java/awais/instagrabber/models/NotificationModel.java b/app/src/main/java/awais/instagrabber/models/NotificationModel.java deleted file mode 100755 index 4ca34b2d..00000000 --- a/app/src/main/java/awais/instagrabber/models/NotificationModel.java +++ /dev/null @@ -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; } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java index edc1e149..cd9ec396 100644 --- a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java @@ -2,6 +2,8 @@ package awais.instagrabber.repositories; import java.util.Map; +import awais.instagrabber.repositories.responses.AymlResponse; +import awais.instagrabber.repositories.responses.NewsInboxResponse; import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; @@ -16,9 +18,9 @@ public interface NewsRepository { Call webInbox(@Header("User-Agent") String userAgent); @GET("/api/v1/news/inbox/") - Call appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen); + Call appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen); @FormUrlEncoded @POST("/api/v1/discover/ayml/") - Call getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map form); + Call getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map form); } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/AymlResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/AymlResponse.java new file mode 100644 index 00000000..5762e170 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/AymlResponse.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/AymlUser.java b/app/src/main/java/awais/instagrabber/repositories/responses/AymlUser.java new file mode 100644 index 00000000..7f5b2632 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/AymlUser.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/AymlUserList.java b/app/src/main/java/awais/instagrabber/repositories/responses/AymlUserList.java new file mode 100644 index 00000000..47b2c112 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/AymlUserList.java @@ -0,0 +1,15 @@ +package awais.instagrabber.repositories.responses; + +import java.util.List; + +public class AymlUserList { + private final List suggestions; + + public AymlUserList(final List suggestions) { + this.suggestions = suggestions; + } + + public List getSuggestions() { + return suggestions; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java new file mode 100644 index 00000000..5dcdb487 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NewsInboxResponse.java @@ -0,0 +1,29 @@ +package awais.instagrabber.repositories.responses; + +import java.util.List; + +public class NewsInboxResponse { + private final NotificationCounts counts; + private final List newStories; + private final List oldStories; + + public NewsInboxResponse(final NotificationCounts counts, + final List newStories, + final List oldStories) { + this.counts = counts; + this.newStories = newStories; + this.oldStories = oldStories; + } + + public NotificationCounts getCounts() { + return counts; + } + + public List getNewStories() { + return newStories; + } + + public List getOldStories() { + return oldStories; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/Notification.java b/app/src/main/java/awais/instagrabber/repositories/responses/Notification.java new file mode 100644 index 00000000..d81bf357 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/Notification.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java new file mode 100644 index 00000000..f66361fa --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java @@ -0,0 +1,86 @@ +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 media; + private final double timestamp; + private final String profileName; + private final String fullName; // for AYML, not naturally generated + + public NotificationArgs(final String text, + final String richText, // for AYML, this is the algorithm + final long profileId, + final String profileImage, + final List media, + final double timestamp, + final String profileName, + final String fullName) { + this.text = text; + this.richText = richText; + this.profileId = profileId; + this.profileImage = profileImage; + this.media = media; + this.timestamp = timestamp; + this.profileName = profileName; + this.fullName = fullName; + } + + 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 getMedia() { + return media; + } + + public double getTimestamp() { + return timestamp; + } + + @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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java new file mode 100644 index 00000000..38fb70f9 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationCounts.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java new file mode 100644 index 00000000..3ba92ce2 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationImage.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/UserInfo.java b/app/src/main/java/awais/instagrabber/repositories/responses/UserInfo.java deleted file mode 100644 index d85f5161..00000000 --- a/app/src/main/java/awais/instagrabber/repositories/responses/UserInfo.java +++ /dev/null @@ -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 + '\'' + - '}'; - } -} diff --git a/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java b/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java index f0ccea70..bdadac87 100644 --- a/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java +++ b/app/src/main/java/awais/instagrabber/services/ActivityCheckerService.java @@ -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 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) diff --git a/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java index aa8fc194..59a8bb64 100644 --- a/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java +++ b/app/src/main/java/awais/instagrabber/viewmodels/NotificationViewModel.java @@ -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; + private MutableLiveData> list; - public MutableLiveData> getList() { + public MutableLiveData> getList() { if (list == null) { list = new MutableLiveData<>(); } diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index 2eca1769..b450312c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -9,17 +9,23 @@ 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.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 +58,31 @@ public class NewsService extends BaseService { } public void fetchAppInbox(final boolean markAsSeen, - final ServiceCallback> callback) { - final List result = new ArrayList<>(); - final Call request = repository.appInbox(appUa, markAsSeen); - request.enqueue(new Callback() { + final ServiceCallback> callback) { + final Call request = repository.appInbox(appUa, markAsSeen); + request.enqueue(new Callback() { @Override - public void onResponse(@NonNull final Call call, @NonNull final Response response) { - final String body = response.body(); + public void onResponse(@NonNull final Call call, @NonNull final Response 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 result = new ArrayList<>(); + result.addAll(body.getNewStories()); + result.addAll(body.getOldStories()); + callback.onSuccess(result); } @Override - public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { callback.onFailure(t); // Log.e(TAG, "onFailure: ", t); } }); } - public void fetchWebInbox(final boolean markAsSeen, - final ServiceCallback> callback) { + public void fetchWebInbox(final ServiceCallback> callback) { final Call request = repository.webInbox(browserUa); request.enqueue(new Callback() { @Override @@ -104,7 +93,7 @@ public class NewsService extends BaseService { return; } try { - final List result = new ArrayList<>(); + final List result = new ArrayList<>(); final JSONObject page = new JSONObject(body) .getJSONObject("graphql") .getJSONObject("user"); @@ -124,16 +113,24 @@ 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 + ), + type, + data.getString(Constants.EXTRAS_ID) + )); } } @@ -144,15 +141,20 @@ 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") + ), + "REQUEST", + data.getString(Constants.EXTRAS_ID) + )); } } callback.onSuccess(result); @@ -169,40 +171,8 @@ 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> callback) { + final ServiceCallback> callback) { final Map form = new HashMap<>(); form.put("_uuid", UUID.randomUUID().toString()); form.put("_csrftoken", csrfToken); @@ -210,57 +180,46 @@ public class NewsService extends BaseService { form.put("device_id", UUID.randomUUID().toString()); form.put("module", "discover_people"); form.put("paginate", "false"); - final Call request = repository.getAyml(appUa, form); - request.enqueue(new Callback() { + final Call request = repository.getAyml(appUa, form); + request.enqueue(new Callback() { @Override - public void onResponse(@NonNull final Call call, @NonNull final Response response) { - final String body = response.body(); + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final AymlResponse body = response.body(); if (body == null) { callback.onSuccess(null); return; } - try { - final List 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 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 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() + ), + "AYML", + i.getUuid() + ); + }) + .collect(Collectors.toList()); + callback.onSuccess(newsItems); } @Override - public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + public void onFailure(@NonNull final Call 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); - } } From b992456a2c05ac92c6eb946563db35088d2878a3 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 4 Mar 2021 15:31:16 -0500 Subject: [PATCH 3/7] add @Zopieux for #609 --- .all-contributorsrc | 9 +++++++++ README.md | 17 +++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index ac44348d..edf8dd87 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -42,6 +42,15 @@ "bug" ] }, + { + "login": "Zopieux", + "name": "Alexandre Macabies", + "avatar_url": "https://avatars.githubusercontent.com/u/81353?v=4", + "profile": "https://github.com/Zopieux", + "contributions": [ + "code" + ] + }, { "login": "MeLlamoPablo", "name": "Pablo Rodríguez", diff --git a/README.md b/README.md index d3671d60..8480e67d 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## THERE ARE CURRENTLY NO OFFICIAL GOOGLE PLAY RELEASES. PLEASE REPORT ANY OCCURRENCES TO US. +### THERE ARE CURRENTLY NO OFFICIAL GOOGLE PLAY RELEASES. PLEASE REPORT ANY OCCURRENCES TO US. Barinsta logo @@ -9,7 +9,7 @@ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE) [![GitHub stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://GitHub.com/austinhuang0131/barinsta/stargazers/) -[![All Contributors](https://img.shields.io/badge/all_contributors-38-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-39-orange.svg)](#contributors) Instagram client; previously known as InstaGrabber. @@ -57,51 +57,52 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
Austin Huang

💻 📖 💬 🌍 🤔
Ammar Githam

💻 🎨 🤔 🚧 💬
Anderson Mesquita

💻 🐛 +
Alexandre Macabies

💻
Pablo Rodríguez

💻
AWAiS

💻 -
Stefan Najdovski

🎨 🌍 +
Stefan Najdovski

🎨 🌍
CrazyMarvin

💵
Kevin Thomas

💵
Shadowspear123

📝 🐛 🤔 💬
Ricardo

🐛 🌍
Airikr

🤔 💬 -
Akrai

🤔 🌍 +
Akrai

🤔 🌍
avtkal

🌍
Cézar Augusto

🌍
Dimitris T

🌍
farzadx

🌍
Fatih Aydın

🌍 -
fouze555

🌍 +
fouze555

🌍
Galang23

🌍
Initdebugs

🌍
Jakub Janek

🌍
GenosseFlosse

🌍
kernoeb

🌍 -
MoaufmKlo

🌍 +
MoaufmKlo

🌍
nalinalini

🌍
peterge1998

🌍
PierreM0

🌍
RAMAR-RAR

🌍
rohang02

🌍 -
retiolus

🌍 +
retiolus

🌍
rikishi0071

🌍
Alexey Peschany

🌍
Still Hsu

🌍
Ten_Lego

🌍
wagnim

🌍 -
wokija

🌍 +
wokija

🌍
ysakamoto

🌍
ZDVokoun

🌍 From a37bb2d1852d4cc968fd27c772b9e693962cb5bd Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 5 Mar 2021 10:50:10 -0500 Subject: [PATCH 4/7] implement profile context (backend) --- .../instagrabber/asyncs/CommentsFetcher.java | 6 +- .../fragments/main/ProfileFragment.java | 28 +++++++++- .../repositories/responses/User.java | 55 +++++-------------- .../responses/UserProfileContextLink.java | 21 +++++++ .../instagrabber/utils/ResponseBodyUtils.java | 2 +- .../webservices/GraphQLService.java | 4 ++ .../webservices/StoriesService.java | 4 ++ 7 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/UserProfileContextLink.java diff --git a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java index 6b9929c5..b5ba3d27 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java @@ -115,7 +115,7 @@ public final class CommentsFetcher extends AsyncTask { final NavController navController = NavHostFragment.findNavController(this); @@ -757,6 +762,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 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); diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/User.java b/app/src/main/java/awais/instagrabber/repositories/responses/User.java index efae4dbf..12f23fdd 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/User.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/User.java @@ -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,8 @@ public class User implements Serializable { private final long usertagsCount; private final String publicEmail; private final HdProfilePicUrlInfo hdProfilePicUrlInfo; - + private final String profileContext; + private final List profileContextLinksWithUserIds; public User(final long pk, final String username, @@ -51,7 +53,9 @@ 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 profileContextLinksWithUserIds) { this.pk = pk; this.username = username; this.fullName = fullName; @@ -75,6 +79,8 @@ public class User implements Serializable { this.usertagsCount = usertagsCount; this.publicEmail = publicEmail; this.hdProfilePicUrlInfo = hdProfilePicUrlInfo; + this.profileContext = profileContext; + this.profileContextLinksWithUserIds = profileContextLinksWithUserIds; } public long getPk() { @@ -173,46 +179,13 @@ 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 List getProfileContextLinks() { + return profileContextLinksWithUserIds; + } @Override public boolean equals(final Object o) { diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/UserProfileContextLink.java b/app/src/main/java/awais/instagrabber/repositories/responses/UserProfileContextLink.java new file mode 100644 index 00000000..7beb954d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/UserProfileContextLink.java @@ -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; + } +} diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 43b24637..30d5ed21 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -782,7 +782,7 @@ 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); } final String id = feedItem.getString(Constants.EXTRAS_ID); final ImageVersions2 imageVersions2 = new ImageVersions2( diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index 74044d29..aa6a29bd 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -243,6 +243,8 @@ public class GraphQLService extends BaseService { null, 0, null, + null, + null, null )); // userModels.add(new ProfileModel(userObject.optBoolean("is_private"), @@ -334,6 +336,8 @@ public class GraphQLService extends BaseService { url, 0, null, + null, + null, null)); } catch (JSONException e) { Log.e(TAG, "onResponse", e); diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index 3f84226c..faf00f6c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -172,6 +172,8 @@ public class StoriesService extends BaseService { null, 0, null, + null, + null, null ); final String id = node.getString("id"); @@ -231,6 +233,8 @@ public class StoriesService extends BaseService { null, 0, null, + null, + null, null ); final String id = node.getString("id"); From 508a80be530c0c7d0f79ac88069e5cb8dc80d909 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 5 Mar 2021 11:44:42 -0500 Subject: [PATCH 5/7] changing profile layout... again --- .../fragments/main/ProfileFragment.java | 9 +- .../res/layout/layout_profile_details.xml | 250 ++++++++++-------- app/src/main/res/values/strings.xml | 10 +- 3 files changed, 154 insertions(+), 115 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index d2f20cc1..86b1504a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -438,6 +438,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe @Override public void onRefresh() { + profileDetailsBinding.countsBarrier.setVisibility(View.GONE); profileDetailsBinding.mainProfileImage.setVisibility(View.INVISIBLE); fetchProfileDetails(); } @@ -655,6 +656,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(); @@ -857,13 +860,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); diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index c54fca8c..c20bcfe3 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -16,53 +16,27 @@ android:transitionName="profile_pic" android:visibility="invisible" app:actualImageScaleType="centerCrop" - app:layout_constraintEnd_toStartOf="@id/mainPostCount" + app:layout_constraintEnd_toStartOf="@id/btnFollow" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="@id/fav_chip" - tools:background="@mipmap/ic_launcher" /> + app:layout_constraintBottom_toBottomOf="@id/btnTagged" + tools:visibility="visible" + tools:foreground="@mipmap/ic_launcher" /> + - - - - + + + + + @@ -104,24 +109,40 @@ app:chipBackgroundColor="@null" app:chipIcon="@drawable/ic_outline_person_pin_24" app:chipIconTint="@color/deep_orange_800" - app:layout_constraintStart_toEndOf="@id/fav_chip" - app:layout_constraintTop_toTopOf="@id/fav_chip" + app:layout_constraintStart_toEndOf="@id/mainProfileImage" + app:layout_constraintTop_toBottomOf="@id/fav_chip" app:rippleColor="@color/deep_orange_400" tools:visibility="visible" /> + + @@ -165,14 +187,17 @@ android:id="@+id/mainBiography" android:layout_width="0dp" android:layout_height="wrap_content" - android:padding="8dp" android:background="?android:selectableItemBackground" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:paddingTop="4dp" + android:paddingBottom="4dp" android:textAppearance="@style/TextAppearance.AppCompat.Body1" app:layout_constraintBottom_toTopOf="@id/mainUrl" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/mainFullName" - tools:text="THE GLORIOUS (step)OWNER OF THIS APP. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec id justo lorem. In malesuada feugiat ornare. Suspendisse et mauris imperdiet, luctus augue eget, tempus eros. Cras vitae molestie ipsum. " /> + tools:text="One of THE GLORIOUS OWNERS OF THIS APP. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec id justo lorem. In malesuada feugiat ornare. Suspendisse et mauris imperdiet, luctus augue eget, tempus eros. Cras vitae molestie ipsum. " /> - - - + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:paddingTop="4dp" + android:paddingBottom="8dp" + android:gravity="center" + android:textAppearance="@style/TextAppearance.AppCompat" + app:layout_constraintBottom_toBottomOf="@id/highlights_barrier" + app:layout_constraintEnd_toStartOf="@id/mainFollowers" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/counts_barrier" + tools:text="35\nPosts" /> - + + + app:layout_constraintStart_toEndOf="@id/mainFollowers" + app:layout_constraintTop_toBottomOf="@id/counts_barrier" + tools:text="64\nFollowing" /> + app:barrierDirection="bottom" /> Import/Export
Language - %s Post - %s Posts + %s\nPost + %s\nPosts - %s Follower - %s Followers + %s\nFollower + %s\nFollowers - %s Following + %s\nFollowing Autoplay videos Always mute videos Always show post captions From 8105462acb228f823295b32077650fbffcf7a4dd Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 5 Mar 2021 14:06:27 -0500 Subject: [PATCH 6/7] add suggestion chaining --- .../viewholder/NotificationViewHolder.java | 8 ++- .../instagrabber/asyncs/CommentsFetcher.java | 8 +-- .../NotificationsViewerFragment.java | 54 ++++++++++++------- .../fragments/main/ProfileFragment.java | 43 +++++++++++---- .../settings/MorePreferencesFragment.java | 4 +- .../repositories/NewsRepository.java | 4 ++ .../responses/NotificationArgs.java | 9 +++- .../repositories/responses/User.java | 9 +++- .../instagrabber/utils/ResponseBodyUtils.java | 3 +- .../webservices/GraphQLService.java | 2 + .../instagrabber/webservices/NewsService.java | 52 ++++++++++++++++-- .../webservices/StoriesService.java | 2 + app/src/main/res/layout/item_notification.xml | 15 ++++++ app/src/main/res/menu/profile_menu.xml | 6 +++ .../navigation/direct_messages_nav_graph.xml | 3 ++ .../res/navigation/discover_nav_graph.xml | 3 ++ .../main/res/navigation/feed_nav_graph.xml | 3 ++ .../main/res/navigation/more_nav_graph.xml | 3 ++ .../notification_viewer_nav_graph.xml | 3 ++ .../main/res/navigation/profile_nav_graph.xml | 3 ++ .../main/res/navigation/saved_nav_graph.xml | 9 ---- 21 files changed, 194 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java index 0d03f9c0..79e84be5 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/NotificationViewHolder.java @@ -59,8 +59,10 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder { } 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); @@ -72,6 +74,8 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder { binding.tvDate.setText(args.getDateTime()); } + binding.isVerified.setVisibility(args.isVerified() ? View.VISIBLE : View.GONE); + binding.tvUsername.setText(args.getUsername()); binding.ivProfilePic.setImageURI(args.getProfilePic()); binding.ivProfilePic.setOnClickListener(v -> { diff --git a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java index b5ba3d27..48dcc401 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java @@ -115,7 +115,8 @@ public final class CommentsFetcher extends AsyncTask> cb = new ServiceCallback>() { + @Override + public void onSuccess(final List 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) { @@ -181,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); @@ -190,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 @@ -217,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); @@ -231,8 +256,10 @@ 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": + if (actionBar != null) actionBar.setTitle(R.string.action_notif); new NotificationsFetcher(true, new FetchListener>() { @Override public void onResult(final List notificationModels) { @@ -251,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>() { - @Override - public void onSuccess(final List 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; } } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 86b1504a..a90bac90 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -56,7 +56,6 @@ import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; import awais.instagrabber.adapters.FeedAdapterV2; import awais.instagrabber.adapters.HighlightsAdapter; -import awais.instagrabber.asyncs.CreateThreadAction; import awais.instagrabber.asyncs.ProfileFetcher; import awais.instagrabber.asyncs.ProfilePostFetchService; import awais.instagrabber.asyncs.UsernameFetcher; @@ -125,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 selectedFeedModels; @@ -364,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); + } } } @@ -433,6 +453,12 @@ 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); } @@ -884,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; } } diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 55088c8b..fce752e1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -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; })); diff --git a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java index cd9ec396..0cc89739 100644 --- a/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/NewsRepository.java @@ -4,6 +4,7 @@ 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; @@ -23,4 +24,7 @@ public interface NewsRepository { @FormUrlEncoded @POST("/api/v1/discover/ayml/") Call getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map form); + + @GET("/api/v1/discover/chaining/") + Call getChaining(@Header("User-Agent") String userAgent, @Query(value = "target_id") long targetId); } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java index f66361fa..87116896 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/NotificationArgs.java @@ -20,6 +20,7 @@ public class NotificationArgs { 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 @@ -28,7 +29,8 @@ public class NotificationArgs { final List media, final double timestamp, final String profileName, - final String fullName) { + final String fullName, + final boolean isVerified) { this.text = text; this.richText = richText; this.profileId = profileId; @@ -37,6 +39,7 @@ public class NotificationArgs { this.timestamp = timestamp; this.profileName = profileName; this.fullName = fullName; + this.isVerified = isVerified; } public String getText() { @@ -67,6 +70,10 @@ public class NotificationArgs { return timestamp; } + public boolean isVerified() { + return isVerified; + } + @NonNull public String getDateTime() { return Utils.datetimeParser.format(new Date(Math.round(timestamp * 1000))); diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/User.java b/app/src/main/java/awais/instagrabber/repositories/responses/User.java index 12f23fdd..3d19077e 100644 --- a/app/src/main/java/awais/instagrabber/repositories/responses/User.java +++ b/app/src/main/java/awais/instagrabber/repositories/responses/User.java @@ -30,6 +30,7 @@ public class User implements Serializable { private final HdProfilePicUrlInfo hdProfilePicUrlInfo; private final String profileContext; private final List profileContextLinksWithUserIds; + private final String socialContext; public User(final long pk, final String username, @@ -55,7 +56,8 @@ public class User implements Serializable { final String publicEmail, final HdProfilePicUrlInfo hdProfilePicUrlInfo, final String profileContext, - final List profileContextLinksWithUserIds) { + final List profileContextLinksWithUserIds, + final String socialContext) { this.pk = pk; this.username = username; this.fullName = fullName; @@ -81,6 +83,7 @@ public class User implements Serializable { this.hdProfilePicUrlInfo = hdProfilePicUrlInfo; this.profileContext = profileContext; this.profileContextLinksWithUserIds = profileContextLinksWithUserIds; + this.socialContext = socialContext; } public long getPk() { @@ -183,6 +186,10 @@ public class User implements Serializable { return profileContext; } + public String getSocialContext() { + return socialContext; + } + public List getProfileContextLinks() { return profileContextLinksWithUserIds; } diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 30d5ed21..f1281d76 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -782,7 +782,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, 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( diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index aa6a29bd..2af7738c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -245,6 +245,7 @@ public class GraphQLService extends BaseService { null, null, null, + null, null )); // userModels.add(new ProfileModel(userObject.optBoolean("is_private"), @@ -338,6 +339,7 @@ public class GraphQLService extends BaseService { null, null, null, + null, null)); } catch (JSONException e) { Log.e(TAG, "onResponse", e); diff --git a/app/src/main/java/awais/instagrabber/webservices/NewsService.java b/app/src/main/java/awais/instagrabber/webservices/NewsService.java index b450312c..a03ca36d 100644 --- a/app/src/main/java/awais/instagrabber/webservices/NewsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/NewsService.java @@ -21,6 +21,7 @@ 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; @@ -126,7 +127,8 @@ public class NewsService extends BaseService { )), data.getLong("timestamp"), user.getString("username"), - null + null, + false ), type, data.getString(Constants.EXTRAS_ID) @@ -150,7 +152,8 @@ public class NewsService extends BaseService { null, 0L, data.getString("username"), - data.optString("full_name") + data.optString("full_name"), + data.optBoolean("is_verified") ), "REQUEST", data.getString(Constants.EXTRAS_ID) @@ -172,6 +175,7 @@ public class NewsService extends BaseService { } public void fetchSuggestions(final String csrfToken, + final String deviceUuid, final ServiceCallback> callback) { final Map form = new HashMap<>(); form.put("_uuid", UUID.randomUUID().toString()); @@ -205,7 +209,8 @@ public class NewsService extends BaseService { null, 0L, u.getUsername(), - u.getFullName() + u.getFullName(), + u.isVerified() ), "AYML", i.getUuid() @@ -222,4 +227,45 @@ public class NewsService extends BaseService { } }); } + + public void fetchChaining(final long targetId, final ServiceCallback> callback) { + final Call request = repository.getChaining(appUa, targetId); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final UserSearchResponse body = response.body(); + if (body == null) { + callback.onSuccess(null); + return; + } + + final List 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 call, @NonNull final Throwable t) { + callback.onFailure(t); + // Log.e(TAG, "onFailure: ", t); + } + }); + } } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index faf00f6c..96e6866f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -174,6 +174,7 @@ public class StoriesService extends BaseService { null, null, null, + null, null ); final String id = node.getString("id"); @@ -235,6 +236,7 @@ public class StoriesService extends BaseService { null, null, null, + null, null ); final String id = node.getString("id"); diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml index f17f2c6c..d12c365b 100644 --- a/app/src/main/res/layout/item_notification.xml +++ b/app/src/main/res/layout/item_notification.xml @@ -45,6 +45,21 @@ app:layout_constraintTop_toTopOf="parent" tools:text="username" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/direct_messages_nav_graph.xml b/app/src/main/res/navigation/direct_messages_nav_graph.xml index d616f202..a324ff1a 100644 --- a/app/src/main/res/navigation/direct_messages_nav_graph.xml +++ b/app/src/main/res/navigation/direct_messages_nav_graph.xml @@ -41,6 +41,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + diff --git a/app/src/main/res/navigation/discover_nav_graph.xml b/app/src/main/res/navigation/discover_nav_graph.xml index 7b8b83e3..3a2f8483 100644 --- a/app/src/main/res/navigation/discover_nav_graph.xml +++ b/app/src/main/res/navigation/discover_nav_graph.xml @@ -89,6 +89,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + + diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml index dd199b6f..f4861fc3 100644 --- a/app/src/main/res/navigation/more_nav_graph.xml +++ b/app/src/main/res/navigation/more_nav_graph.xml @@ -54,6 +54,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + + diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml index e26b966e..f84af5f5 100644 --- a/app/src/main/res/navigation/profile_nav_graph.xml +++ b/app/src/main/res/navigation/profile_nav_graph.xml @@ -80,6 +80,9 @@ android:name="type" app:argType="string" app:nullable="false" /> + diff --git a/app/src/main/res/navigation/saved_nav_graph.xml b/app/src/main/res/navigation/saved_nav_graph.xml index 6813d98c..805a06e5 100644 --- a/app/src/main/res/navigation/saved_nav_graph.xml +++ b/app/src/main/res/navigation/saved_nav_graph.xml @@ -64,15 +64,6 @@ app:nullable="false" /> - - - - Date: Fri, 5 Mar 2021 14:18:51 -0500 Subject: [PATCH 7/7] fix unread threads typeface, close #463 --- .../viewholder/directmessages/DirectInboxItemViewHolder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectInboxItemViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectInboxItemViewHolder.java index 85373901..dfecaa0c 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectInboxItemViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectInboxItemViewHolder.java @@ -356,7 +356,7 @@ public final class DirectInboxItemViewHolder extends RecyclerView.ViewHolder { final Map lastSeenAtMap = thread.getLastSeenAt(); final boolean read = ResponseBodyUtils.isRead(item, lastSeenAtMap, Collections.singletonList(thread.getViewerId()), thread.getDirectStory()); 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); } } \ No newline at end of file